home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
keyb
/
alias450.zip
/
ALIAS.ASM
next >
Wrap
Assembly Source File
|
1990-02-04
|
236KB
|
6,113 lines
Title ALIAS.COM Command line editor/abbreviator for MS-DOS
comment | ; start of comment block
A L I I I I I A S S S
A A L I A A S S
A A L I A A S
A A L I A A S S S
A A A A A L I A A A A A S
A A L I A A S S
A A L L L L L I I I I I A A S S S
-----------------------------------------------------------------------
F U N C T I O N
-----------------------------------------------------------------------
This program adds a number of resident commands to DOS to implement a
form of the Alias command as found on other computers. See the variables
area under 'help_text' for a list of the facilities provided, or install
it by typing ALIAS at the DOS prompt, and then view the help screen by
typing ALIAS ? at the prompt.
Like aliases, DOS commands typed at the prompt can be split with
the & character, as long as aliases are turned on (type ALIAS ? at the
prompt, for help).
ALIAS also incorporates a DOSEDIT-like facility, so ALIAS is a full
superset of DOSEDIT, CED and the like.
Also, command completion is offered. Type the first few characters of a
command and press the prf_trigger key. If a matching command is found, it
will be put on screen to complete the part-typed command. See the code
for the definition of the prf_trigger key. Why prf? Well, during development
it was known as parameter recall facility.
This file (ALIAS.ASM) comprises the entire source code. No other files
are needed to create ALIAS.COM. The help text is a plain ASCII file called
ALIAS.HLP.
Note that this resident program uses the default MS-DOS stack and does not
create its own. This has not caused any known problems. (The DOSEDIT code
sets up its own stack, but the rest of ALIAS does not use it, yet).
-----------------------------------------------------------------------
I M P O R T A N T N O T E S
-----------------------------------------------------------------------
1. This source code is made available for personal use only. You can
learn from it, steal my routines, and make your own custom
versions of the program.
YOU MUST NOT make your own customised or enhanced versions generally
available on any BBS or by any other means.
The only way to incorporate your enhancements into the distribution
version of ALIAS is to send ideas or code fragments (not whole new copies
of this file, please!) to the author.
2. If you start changing the code in here, some things may not work properly.
Just because the table size is defined as an equate, this does not mean
that you can necessarily enlarge the table by simply changing the equate.
If you change the code, and your machine crashes, that's not my fault.
3. There are two conditional assembly instructions in the code. If DEBUG is
set, a number of debug procedures wil be assembled but not called. They
can be called by inserting CALL commands as required. If ONLINE_HELP is
set, the online help will be available, as documented, with the ALIAS ?
command. If ONLINE_HELP is not set, the online help is not assembled, and
is replaced with a short message to this effect. This saves around 2K of
RAM when ALIAS is loaded, but means that users will have to read the
ALIAS.HLP documentation file to get help.
-----------------------------------------------------------------------
B U G F I X E S A N D A M E N D M E N T S T O B E D O N E
-----------------------------------------------------------------------
Add DOS compatibility with function keys for Psion. To do by mid Jan 1990.
Should PgUp and PgDn redraw the display line?
Trap func 29h, which the batch file interpreter uses to parse strings. Copy
commands retrieved from batch files, into the ALIAS history buffer.
Add an ALIAS E command to edit an alias, or do separate ALIAS2WP and WP2ALIAS
file conversion programs. If programs, make one prog. Use Basic 7?
ALIAS D has the colour bug if used on the bottom line.
Add an extended keyboard buffer to 128 bytes. This may be difficult, as DOS 4
is too large to keep the buffer within segment 40h.
Add executable filenames? eg ALIAS A *.ASM PE *.ASM, ie the asterisk
stands for the primary filename in both sides of the alias definition.
The code for ALIAS A already permits this, so it's just the expander that
needs expanding!
Ignore separator characters unless surrounded by spaces, else the user can't
have filenames with ampersands in.
The colour bug is still in ALIAS S.
There's a problem when PC-Tools is loaded resident.
There's a problem with Borland's Sprint. See message on Cix for more.
Multiple-command lines can't have nested aliases. Eg, if you
have ALIAS A CD CHDIR then CD FRED & DIR will use CD and not CHDIR
to change directories. Demon@Cix found this bug, so mail him when
it's fixed. Reported in exe/files #250 on Cix.
There are problems with Sidekick Plus. See message on Cix.
If SHOW mode is on and user types 11&22, the 22 gets echoed twice. It seems
that echo proc is being called from both 'call echo' statements.
-----------------------------------------------------------------------
D E V E L O P M E N T E N V I R O N M E N T
-----------------------------------------------------------------------
Machine: CompuAdd 386/20 & other PC clones
Operating System: MS-DOS 4.01. Will run under DOS 2, 3 or 4 or 10.
Language: 8086 assembly language
Assembler: SLR Systems OPTASM version 1.5.
Linker: Microsoft Linker version 5.01.20
Program Format: Must be run as a .COM file, not .EXE
Editor for source file: Word Perfect Program Editor version 4.21.
-----------------------------------------------------------------------
C R E A T I N G E X E C U T A B L E F I L E
-----------------------------------------------------------------------
ALIAS is designed to run as a .COM file and MUST do so. Strange things will
happen if you make this into an .EXE file, because ALIAS.COM uses parts of
its PSP as buffer space, and does other things which make assumptions about
segments and their position in memory.
To create ALIAS.COM:
1. MASM ALIAS; <---- note the semi colon
2. LINK ALIAS; <---- and this one, too
3. EXE2BIN ALIAS
4. RENAME ALIAS.BIN ALIAS.COM
5. DELETE ALIAS.EXE
6. DELETE ALIAS.OBJ
-----------------------------------------------------------------------
S T R U C T U R E O F D A T A
-----------------------------------------------------------------------
The alias table consists of a contiguous block of bytes, each initialized
to zero. Each entry in the table consists of a left hand side and a right
hand side. The length of the left hand side and right hand side, as well as
the number of entries, are fixed by the equates LHS_LEN, RHS_LEN and TBL_LEN
respectively. These can be changed prior to reassembling this program,
resulting in an ALIAS.COM of any desired length. The table is a fixed-length
structure, which is probably not the best way to have written it.
After the right hand side part of a table entry comes a zero to signify the
end of an entry. This extra byte is not included in the count of characters
defined in the equates.
If a table entry is empty, the first byte is 0. If the entry is full, the
first byte is non-zero, there is a string on the right and left side, and ALL
unused bytes in the entry are 0.
There are 5 bytes before the actual table data. These are saved along with
the data, but are not flushed by the ALIAS F command. These 5 bytes are:
1: - ins_mode. 0 = overwrite, 1 = insert.
2: - status. 0 = abbrevs turned off, 1 = on
3: - expand_from. If 1, global, 0 = DOS prompt only
4: - screen colour.
5: - echo_status. Shows whether Show or Hide mode set.
There is no identifying string to show that the file is an ALIAS file, or
to specify the lhs and rhs lengths.
These flags will need bitmapping if any more data is required to be saved.
-------------------------------------------------------------------------
H I S T O R Y O F T H I S V E R S I O N
-------------------------------------------------------------------------
4.50 Started adding touches of DOS compatibility to the line editor.
INS and Del work vaguely like DOS!
4.30 Changed function keys around. Command completion now F8.
'It' and 'Also' are F9 and F10 respectively. This leaves F1 to F5
free, to add full DOS function key compatibility at a later stage.
4.27 Removed help_flag (originally added in v4.12) and added function key
line to help text.
Changed literal arrow characters in help text to decimal numbers, cos
the Ctrl-X was screwing up printer listings of the source code.
4.26 Increased length of command completion buffer from 1000 to 1500 chars.
This value is held in CmdLen.
4.25 ZAP_MSG shortened to save memory. Also, error_msg and disk_msg, and
version.
Added an online_help conditional assembly switch. When true, the help
text is assembled. Otherwise, no online help is assembled, saving RAM.
UK registration price increased from £20 to £25.
Made parameter recall (the F4 key) case-insensitive, by forcing chars
to lower case before comparing them in prf_compare.
Made putc routine use DOS rather than the BIOS version that was in NDE.
Rewrote the sign-on text.
Amended some calls to bios_video, so they preserve more registers in
order to conform to what the IBM tech ref says about int 10h's use
and corruption of registers. Should always preserve ax,bp,si and di.
4.24 Greeting message is now printed by a DOS call, rather than using our
home-made bios version. The whole greet message can consequently be
redirected to NUL if it is not required.
Dialcom reference removed from greeting, cos I'm not on Dialcom any more.
4.23 Fixed printregs cos it used to corrupt bp and si.
4.22 Added check to see if user just types a single ampersand as a string.
If so, kill the string, or ALIAS goes into a loop.
Removed all traces of par_flag. This was a flag that used to be set
if the string typed at the prompt was found in the alias table. If it
was set, then replace_params (no longer used) would put back the params
typed after the first word. Also, echo proc used par_flag, to only echo
in certain cases. Now, if show mode is on, we always echo, whether the
string came from DOS prompt, was part of a multiple line etc.
4.21 Re-implemented filter proc, to filter out LF characters. Sometimes,
strings end with CRLF, and bufkey stops with CR so there will be stray
LF characters around.
Expanded sign-on message.
Uploaded as ALIAS421.COM and .HLP to Bix, 30/4/89.
4.20 Started adding support for % replacable parameters. After calling
SUBST, call expand_percents to substitue the percent parameters into
the ds:dx bufer.
BIOS_BLIP, which makes a beep by using hardware programming and no
bios calls, renamed to hw_blip.
Released on Cix 3am, 23/4/89.
4.18 Removed no_dollar flag. Display routines now stop on ascii zero,
and never on a dollar sign. This allows aliases to contain dollar
signs and to be listed properly.
Added F1proc, that does nothing when F1 is pressed. There is no
need for an F1 key when you have the editing facilities of ALIAS.
4.17 Finally fixed the multiple-size cursor for CGA, EGA, VGA etc.
Works OK now.
4.16 Experimental bug-fix for cursor size on non-CGA machines. Need to
set bit 0 of 0:487?
4.15 Cursor size now indicates insert/overwrite mode.
4.14 Moved insert mode status byte so it gets saved in the data file.
Disabled the filter proc, which prevented control characters being
typed. Added F6 key recognition to getc, to make it Ctrl-Z.
If user doesn't type a space before pressing the IT key, a space
is automatically added to user's string.
Added ESC key to help text.
Added PgUp/Dn commands, and included them in the help text.
Bufkey routine now preserves si, which Norton's version doesn't do.
ALIAS (and NDE) now work properly with MASM.
ALIAS414.COM released on Cix, 11 Feb 1989.
4.12 Removed token parsing from disp_str_colour, cos the help text was
getting very confusing. It is now printed literally.
Rewrote help text to include more information. There are no features
that do not now appear in the help text.
Added help_flag. It is set before the help text is displayed, and
cleared again afterwards. Disp_str_colour puts a white space in column
1 when the flag is set. The help text is shifted right by 1 char.
This means that we can use all 25 lines, without getting the colour
problem, but only 79 of the 80 columns can be used. Oh well.
Added line to de-install message to say that user's command buffer
has been cleared.
Added f3proc, which is called when F3 is pressed. This is a non-
destructive version of cursup, which won't overwrite chars to the
left of the cursor. This is the way that DOS works normally, compared
to the destructive cursup proc that used to be called when F3 pressed.
There is unused code that used to handle F3 before prf and DOSEDIT was
added. This has not yet been removed.
Added shareware message, requesting money, to signon screen.
Added F8 key, which is like F4 but doesn't check to make sure that
the parameters match. It just retrieves all but the first word of
the previous command and takes it on to the word that you have typed.
F8 is known as the IT key, cos you can TYPE a file and then DEL IT,
rather than specifying its name again.
Added no_dollar flag. Normally set to 1, which means that
disp_str_colour will terminate on a dollar sign. Temporarily set
to 0 before displaying the greet message, so that we can have a dollar
character in the sign-on text.
Rewrote help text yet again! disp_str_proc still puts a white space
at the start of each line of the help text, so that the text could
fill the whole screen without corrupting colours. At present, though,
the help text only fills about 18 lines.
Removed ALIAS X and ALIAS Y commands, which used to turn prf on and
off. No longer needed, now prf trigger is not the space bar. People
have suggested that cursor-up should work like the prf key if one or
more characters have been typed. Decided against this, because it
will confuse. After all, why shouldn't it work like F3, instead?
Added the 'also' key, which works in a similar way to the 'it' key.
Eg, TYPE FRED, <ALSO> JIM, thus <ALSO> repeats the TYPE command.
Currently using the F10 key for 'also'. See also_proc.
Added line to ALIAS I info to give number of aliases currently
defined, and the total number of places in the table.
Pressing ESCape allows exit from recursive aliases. This was easier
and safer than adding Ctrl-C checking.
Released on cix in exe/alias 20.1.89.
4.11 Fixed 2 places in ab_add proc, so that aliases of 7 characters or
more get truncated properly and added to the table in the right way.
Previously, the proc was not stepping over any unwanted lhs characters
that were over the lhs length limit.
Also fixed routine at do_again: to put the correct number of characters
into the comparison buffer. 6-character aliases are now accepted, listed
and executed properly.
Changed dates from 1988 to 1989.
Environment block does not get freed if debug flag is set. This lets
SMAP find the name of the loaded program.
Sprinkled a few cld instructions around, to ensure that repeated
mov and sto instructions go in the right direction.
Released on Cix as ALIAS411.ARC on 2 Jan 1989.
4.10 Changed alias i text to talk about command completion and not parameter
recall.
Released on Cix 30.12.88 as ALIAS410.ARC, containing just ALIAS.COM.
4.03 Removed the extra lines in tinyedt that checked for the prf_trigger
key, and replaced them with an entry in cmndtbl. This is the proper
way to do things, and it saves about 150 bytes.
Made prf match with whatever the user has currently typed, rather than
waiting for a whole word to be typed.
Fixed bug from earlier incarnations of the prf procedure that prevented
matches from being found in certain circumstances, by replacing the
charcount routine, that kept track of how many characters the user had
typed, with calls to bublcnt when required. Simply incrementing a
counter after all calls to getc was not good enough, because it didn't
take into account things like presses of the del key.
Changed help text entry for parameter recall to Command Completion,
which is more accurate. Added ALIAS B command to help text, after
its previous, yet temporary, demotion to an undocumented command.
Changed 2 INC SI commands in ab_buffer to calls to cmdinc. This should
fix the problems that were happening with the alias b command.
Added check for multiple presses of the prf trigger key, to bring
back repeated matches if there are any. Multiple presses of the
key now cycle through all matches, then back to the first match
again.
Added printregs proc. Gets assembled only if DEBUG is defined as
non-zero. Calling printregs prints the values of all the registers,
in ascii hex, on LPT1.
4.02 Changed to_lower proc so that, instead of forcing all aliases to
lower case, we now force only the short forms. The long forms,
ie the second string in an ALIAS A command, are now case sensitive.
The short forms are still forced to lower case, so you can not create
an alias called DA if there is an alias called da.
4.01 Added overwrite mode facility to editor, cos all input was in
insert mode. Added entry to cmndtbl, plus extra code to putin.
Also added ins_mode byte in data area, and inskey proc to toggle
the byte when the insert key is pressed.
Changed hard-coded prf trigger key (SPACE character) to one defined
with an equate, so it can easily be changed. Currently set to F4.
4.00 Added PRF, Parameter Recall Facility.
Added code to dosedit routine to watch for first space char in
string, and call do_prf when it's found. Doesn't allow the space
to be the first char.
Amended help text to include ALIAS X and ALIAS Y commands.
Lengthened command table to accept ALIAS X and ALIAS Y.
Added procs to process ALIAS X and ALIAS Y.
Added proc to AB_INFO to display current state of PRF.
Added do_prf proc to handle the display updating and command matching.
Do_prf checks for match and, if found, prf_disp updates display.
Replaced the 01Ah byte, stored at the front of an alias table file,
with the value of prf_flag, so this flag now gets saved in the file.
To update an old data file, from a version of ALIAS less than
4.00, type ALIAS X or ALIAS Y to set prf preference, and re-save the
file with ALIAS W.
Added display-a-white-space routine after ab_buffer to prevent
corruption of display.
Removed ALIAS ? from the help screen, as a shorter help screen cures
the last ocurrence of the display colour bug.
Fixed bug in code that constructed default data file name. If file
was in root, an extra backslash was added. Now works properly.
Added DEBUG flag in equates. If set, BIOS_BLIP gets assembled.
Rewrote do_prf so that the command stack is searched in the correct
order, ie most current commands first. Also takes account of commands
that may wrap around between top and bottom of the command stack.
Added move_crsr proc to prf code so that cursor is placed in correct
position after prf facility is used.
3.04 Changed alias.dat to upper case, so that it looks better when
printed by the alias i command.
Removed DOSEDIT equate, that allowed a version of ALIAS to be
assembled without the DOSEDIT module. This is to prepare for the
parameter recall facility, which will only work when DOSEDIT is loaded,
as we need control over individual keys pressed.
Removed the 'Command Line Editor Available' message from alias i
info, cos it's always available now.
3.03 Rewrote help screen to be task-oriented rather than keystroke
oriented. Token values changed to apply to new help screen.
Removed a call to crlf, to stop leaving 2 blank lines after ALIAS W.
If the default file is loaded at install time, a record of the current
directory is kept. If an ALIAS W command is given, and no file is
specified, the default file written will be placed in the same directory
as the original file was loaded from. If a filename IS given, it will
go in the current directory, or the one specified in the pathname on
the ALIAS W command.
ALIAS R commands work the same. If just ALIAS R is typed, and a
default file was loaded at install time, the ALIAS R command will read
from that same default file, with the same path.
The ALIAS I command shows the full pathname of the current default
file. Note that this default filename cannot be changed.
Added small routine in INSTALL procedure to free the program's
copy of the environment strings. This saves a few bytes of RAM
once the program is installed, though it does mean that programs such
as SMAP and RMAP will not be able to report the name of the program,
as the name is stored at the end of the environment string data.
ALIAS303.ARC, containing just a COM file, released on Cix 18/11/88.
Will not give source code away from now on.
3.02 Changed from Microsoft MASM 5.1 to OPTASM 1.5. No changes at all
required for source code. Assembles faster, and produces a .COM
file around 35 bytes smaller, by optimizing jump instructions.
No OPTASM special features are used, in order to maintain MASM 5
compatibility. This means that pushm and popm are not used, for
example. OPTASM takes care of jumps being out of range, so there
may be a couple of these that need correcting if MASM is used.
Fixed ab_buffer proc so that listings pause after each screen. Added
line to list_pause proc, to clear the counter when the list_proc
routine is called.
Added disclaimer, and removed (c) symbol from help text.
Replaced generic 'There is an error' message with a set of more
specific ones. Procs added are invalid_letter, syntax_error,
exist_err and not_found.
3.01 Fixed bugs caused by block-conversion of the NDE code to lower
case. A few capital letters in quotes got changed to l/case, which
affected CMP instructions.
Removed redundant message that used to be produced after the SORT
command had done its job.
Changed ShrtStr from 2 to 0, so all strings are saved in DOSEDIT
buffer, even if they are only 1 char long. This means that ALIAS B
gives you a true history of what you've typed recently. There should
be an option of saving the history to file, but there isn't yet.
Re-wrote ab_buffer proc so that strings get displayed in the
current colour, and not white.
ALIAS301.ARC RELEASED SEPTEMBER 1988.
ARC FILE INCLUDES ALIAS.ASM AND ALIAS.COM.
DOC FILE FROM v1.31 NOT INCLUDED. SEE THIS HISTORY SECTION INSTEAD.
3.00 Added DOSEDIT-like facility. This is now a standard feature of having
ALIAS loaded, and thus makes it ALIAS a superset of DOSEDIT. Current
DOSEDIT users can be encouraged to replace DOSEDIT with ALIAS v3.00.
At present the DOSEDIT code is based strongly on NDE, a Norton
DOSEDIT clone released as shareware on CompuServe a couple of years
ago. This code will be modified and improved, though.
The parameter recall facility as found in CED is not yet available
with ALIAS. This will come in version 4 of ALIAS, hopefully.
DOSEDIT flag added. If false, program will assemble with old
get-string code, and will not include the DOS editor. Saves around
3K of RAM in the file and the resident code.
Changed int 10h calls in editor code to use bios_video macro.
Added check at install time to permit loading under DOS version 4.x.
Added ALIAS B command. Only assembles if DOSEDIT is true.
2.13 Added message at load time to say we're loading alias.dat.
2.12 Fixed to_lower proc to only convert characters in the range A to Z.
(Note the capitals). If ALL characters are converted, strange things
happen, eg a backslash becomes a pipe character.
Entries in multiple commands can't have overrides.
Eg, ALIAS A ZZ CD\FRED & ~TC stuffs CD\FRED into the buffer, and then
stuffs ~TC (ie, the override char gets stuffed as well.) Also, ~A & B
results in A getting executed but not B. These 'bugs' cured by
officially documenting the fact that overrides are only designed to
override a whole line, and that their use in any other place than the
1st char in a line, or the use of more than 1 override char in a line
will cause unpredictable results.
2.11 Added some tokenising in the HELP text, so that phrases appearing
many times are included in the code only once. Size of .COM file was
reduced by 457 bytes, despite the additional code to process the tokens.
Added crlf to start of list4 label, to prevent corruption of DOS
prompt if ALIAS L xxx failed to find specified entry in table.
2.10 Added checking in replace_params and subst procs, to ensure that
we don't stuff too many characters into the ds:dx buffer. The size
of the buffer is in ds:dx, placed before the function call.
Fixed bug in list routine to handle 40h:84h being 0, in which case
screen length gets set to 25.
Force the parameters of an ALIAS A command to lower case, to prevent
case-sensitive aliases being added to the table.
Added routine after faking a get-string call, to iret if the user
simply presses RETURN. In such a case, no more processing by ALIAS
is necessary.
2.01 Added nesting facility. You can have ALIAS A FA F A:*.*, where the
expanded alias is an alias command in its own right.
Fixed bug in AB_ADD routine that checks whether an alias exists before
allowing one to be added to the table. The check routine checked one
too few entries, so you could add an alias that had the same name as
the last one in the table.
Changed list_pause routine to only pause if screen is really full
(ie, support EGA 43 lines). Also, Press Any Key message is removed
from screeen when key pressed.
Added get_vpage proc, so we now write to the current video page and
don't simply assume page 0. Should really force video page to 0 if
we are in graphics mode, but who has a DOS prompt in graphics mode?!
2.00 Added parameter facility. If F is abbreviated to DIR, then typing
F A: will be expanded to DIR A: and not just DIR.
This is done as follows. When the user's string is first typed,
only the first word (up to a space) is used for deciding if an alias
exists. The rest is just saved away in a buffer. Once the alias
has been substituted, REPLACE_PARAMS is called to put those buffered
characters back where they belong and to update the length pointer
in ds:[dx+1]. In theory, the routine should ensure that the length
of the new string doesn't exceed that specified in [dx] and, if
it does, the string should be truncated. This does not happen in
version 2.00.
Note that replace_params only does something if the search for an
alias succeeds. If the first word that a user types does not appear
in the table, replace_params does nothing.
Note that, in multi-statement lines, any parameters get appended to
THE LAST OF THE STATEMENTS ONLY. So, if you have CLS & DIR, the
parameters would go on to the DIR but not the CLS.
Added AB_ORDER proc to sort the alias table in RAM. This was originally
called by the ALIAS O command but I've changed things so that it gets
called automatically whenever the table changes. This way, the table is
always kept alphabetical for the benefit of the user. Because of this,
it would be better (and faster) if the ADD procedure looked for
spare table entries by starting from the bottom, but doing this is not
really important.
Fixed colour bug. Before, if an ALIAS command causing screen output
made the screen scroll, the DOS default attribute changed to ALIAS's
colour setting. So, an ALIAS L that filled the screen with yellow text
would cause all subsequent DOS output to be in yellow until a CLS.
The cause of this is BIOS video function 0Eh (write TTY). When it
scrolls the screen up, it gets the attributes for the new line from the
line above, which was the coloured text displayed by ALIAS. Fixed by
adding a routine to put a white space at the start of a line, for
function 0Eh to find and copy. This problem doesn't seem to occur if
ANSI.SYS is loaded - perhaps it handles scrolling in a better way.
Expanded the LIST command to stop if screen is full and ask user to
press any key. Essential if you have more than 24 aliases in table.
Install routine now permits loading under DOS major version 2,3 or 10.
Version 10.0 is the DOS box of OS/2.
Replaced int 10h calls with a macro that also preserves bp, cos of bug
in early IBM bios, that trashes bp during an int 10h call.
1.31 Expand_from and ab_status flag bytes moved into the table area, so
they now get saved to disk with the table.
Disk_error_msg proc added. DOS version check now looks for ver 2 or 3,
and not just >1. Prevents prog being used under DOS 4 or OS/2.
ALIAS131.ARC (first ever release of ALIAS) RELEASED DECEMBER 1987.
ARC FILE CONTAINS JUST ALIAS.COM AND DOCUMENTATION.
1.30 Added bp to list of registers in push_all and pop_all macros.
Added shift_left proc, so that leading spaces in user's input are now
handled as they would be if ALIAS were not installed,
1.29 Changed method for checking whether ALIAS is resident. Versions up to
1.28 used a signature. The checking process involved searching all of
RAM for the signature. This was slow, and also meant that, if a copy
of ALIAS.COM was kept on a ram disk, the signature would appear in
memory even if ALIAS was not loaded.
Version 1.29 intercepts int 21h function 35h (get interrupt vector).
Before passing control to the real function 35h routine, the fifth byte
of the inter-application communication area at 0040:00F4h is
incremented. Thus, a program simply needs to do a dummy call to func
35h and monitor the ICA byte, to see whether ALIAS is loaded or not.
The side-effect of this is that calls to function 35h will corrupt
the ICA. If this causes problems it can be fixed, though the very few
programs that actually use the ICA should be responsible enough to
keep a check on its integrity now and again!
1.28 Display error message if invalid ALIAS command typed
1.27 If only 1 parameter is specified in A command, error msg displayed. If
the single parameter followed by a space, abbreviation is set up to
a null string and can be deleted with D.
Error message (no action taken) expanded to give help.
1.26 Check with ALIAS L that user leaves a space between arg and ALIAS L
else machine hangs. Same goes for D and A command.
1.25 Y or N typed to Are You Sure message gets echoed in correct colour
1.24 Only Y,y,N,n allowed in response to 'Are you sure...' msg.
Alrdy_in message expanded.
1.23 Fixed bug so that args specified in D and L command works in u/case too
1.22 List command can now optionally take an argument. Zap_msg tidied up.
Confirmation required on f,r,w,z options.
Added disp_ch CR in echo proc, after echoing ']'. Needed for Infocom
games.
1.21 Echo_status saved with data files.
1.20 Alias commands can now be recalled with F3, just like any DOS command.
The ALIAS Z command can't, though, as the routine that puts the chars
back into the buffer for F3 to find doesn't get called because alias
has been de-installed. Oh well, can't have everything I s'pose.
1.11 Current colour gets saved with the table.
1.10 Fixed colour bugs in ALIAS L and in show mode, where some parts
always displayed in white.
1.00 First version of Alias. Previously called ABR. Commands changed from
AB to ALIAS. Default filename changed from DEFAULT.ABR to ALIAS.DAT
| ; end of comment
; -----------------------------------------------------------------------
; M A C R O S
; -----------------------------------------------------------------------
;
;
show macro string ; Display a string using
push ax ; a DOS call.
push dx
push ds
push cs
pop ds
mov ah,9
mov dx,offset cs:string
int 21h
pop ds
pop dx
pop ax
endm
;
push_m macro arglist
irp register,<arglist>
push register
endm
endm
;
pop_m macro arglist
irp register,<arglist>
pop register
endm
endm
;
disp_ch macro char
push_m <ax,dx>
mov dl,char
mov ah,2
int 21h
pop_m <dx,ax>
endm
;
push_all macro
push_m <ax,bx,cx,dx,di,si,es,ds,bp>
endm
;
pop_all macro
pop_m <bp,ds,es,si,di,dx,cx,bx,ax>
endm
;
bios_video macro
push bp
int 10h
pop bp
endm
;
; -----------------------------------------------------------------------
; E Q U A T E S
; -----------------------------------------------------------------------
;
VERS equ '4.50' ; Current version number.
; Note that this is the only place
; where the version number is quoted
; literally.
DEBUG equ 0 ; Assemble debug procs if <> 0
; Also, don't free environment block
ONLINE_HELP equ 1 ; Only assemble help text if set
RSIZE equ (init-start)/16+17 ; number of resident paragraphs
CR equ 0Dh ; carriage return character
LF equ 0Ah ; line feed character
EOM equ 0 ; message terminator for internal
; display routines.
DOS_EOM equ '$' ; message terminator for strings
; displayed by DOS functions.
BS equ 08 ; backspace
LETTER equ byte ptr cs:command_letter
SPACE equ 20h
WHITE equ 7 ; attribute value
; The following 3 values define the size of the alias table
LHS_LEN equ 06 ; length of lhs in table entry
RHS_LEN equ 70 ; length of rhs
TBL_LEN equ 30 ; no of entries in table
;
OVERRIDE equ '~' ; override character for commands
SEPARATOR equ '&' ; char between cmds on multi-cmd lines
; Extra DOSEDIT equates
PRF_TRIGGER equ 0142h ; F8 key
IT_KEY equ 0143h ; F9 key
ALSO_KEY equ 0144h ; F10 key
MaxSWdt equ 134 ;max screen width
MaxLin equ 140 ;max line length to edit
CmdLen equ 1500 ;number of char for previous commands
ShrtStr equ 0 ;length of strings too short to save
TAB equ 09H ;ASCII tab
ESCAPE equ 1BH ;ASCII escape
HomeKey equ 0147H ;home key
UpArrw equ 0148H ;up arrow key
LtArrw equ 014BH ;left arrow key
RtArrw equ 014DH ;right arrow key
EndKey equ 014FH ;end key
DnArrw equ 0150H ;down arrow key
DelKey equ 0153H ;delete key
CntLf equ 0173H ;control left arrow key
CntRt equ 0174H ;control right arrow key
AltW equ 0111H ;ALT W key
AltL equ 0126H ;ALT L key
AltK equ 0125H ;ALT K key
AltU equ 0116H ;ALT U key
F1Key equ 013BH ; F1 Key.
F3Key equ 013DH ;F3 function key
F6Key equ 0140H ; F6 key.
PGUPKEY equ 0149H ; PgUp Key
PGDNKEY equ 0151H ; PgDn Key
CNTL equ 40H ;difference between alpha and control
Insert equ 0152h ;Insert key
; end of dosedit equates
; -----------------------------------------------------------------------
; S T A R T O F M A I N C O D E
; -----------------------------------------------------------------------
code segment
assume cs:code,ds:code,es:nothing
org 100h
;
start: jmp init ; init code at end of res section
;
private db CR
db 'ALIAS v',VERS,' - (c) Robert Schifreen.',1ah
;
intent: ; DOS function 0Ah comes here now
;
push ax ; first, save the flags reg
pushf ; save flags on stack...
pop ax ; ...and retrieve into ax
mov cs:save_flags,ax
pop ax
cmp ah,0ah ; is this a 'get string' instruction?
je go_on ; continue if it is
cmp ah,35h ; intercept get-int-vector to check for
; alias being resident.
je func35
jmp exec ; else jump far to abort
;
func35: ; we have found a call to function 35h.
; Increment byte 0040:00F4h as a sign
; that ALIAS is resident.
push ds
push ax
mov ax,40h
mov ds,ax ; ds points to ICA segment
inc byte ptr ds:0f4h ; increment 5th byte of ICA
pop ax
pop ds
jmp exec ; and go to real int 21h routine with
; everything intact.
go_on:
;
cmp cs:do_kb_str,0 ; do we want to restore kbd buffer?
je no_restore_kbd ; if not, then don't
call restore_buffer ; put back chars so F3 can find them
mov cs:do_kb_str,0 ; clear the flag now it's dealt with
no_restore_kbd:
push bp ; The first time that the new int 21h
push ax ; handler is called, this routine saves
mov ax,cs:command_cs ; CS and IP values that called it. This
cmp ax,0 ; will be the location in COMMAND.COM
jne csip_saved ; that called it.When other strings are
mov bp,sp ; processed we can get CS and IP values
mov ax,ss:[bp+6] ; from stack (pushed by INT) & cmp
mov cs:command_cs,ax ; them with the stored ones. If they
mov ax,ss:[bp+4] ; match,string being looked at was
mov cs:command_ip,ax ; entered from DOS prompt. If not, str
;
csip_saved: ; must have come from another prog.
;
pop ax
pop bp
;
push ax ; was string typed at the DOS prompt?
push bx ; (See above for how to find out.)
push bp
mov bp,sp
mov ax,ss:[bp+8] ; get CS value that called us.
mov bx,cs:command_cs ; get saved CS value
cmp ax,bx ; are they the same?
jne wrong_csip ; abort if not
;
mov ax,ss:[bp+6] ; get IP value that called us
mov bx,cs:command_ip ; get saved IP value
cmp ax,bx ; same?
jne wrong_csip ; abort if not equal
jmp csip_valid ; continue processing if OK
;
wrong_csip: ; We were not called from COMMAND.COM
; so just get string and return
;
pop bp
pop bx
pop ax
;
; although the string was not
; typed at the DOS prompt, if
; expand_from = 1 then global
; expansion is required so jmp to
; csip_valid anyway
cmp cs:expand_from,1
je csip_valid2
;
cmp cs:multi_line_outstanding,0
je no_need
jmp do_multi_line
;
no_need:
;
call get_string_from_kbd ; else fake a real 'get string' call
call restore_flags ; replace flags saved on entry
iret ; and return to caller of INT 21h
csip_valid: ; CS and IP values correct. Look for ~
pop bp ; tidy up the stack
pop bx
pop ax
; Is there part of a multi-statement
; line that has not been passed to DOS?
; If so, don't read keyboard but go
; straight to correct routine.
csip_valid2: ; come here if global.
;
cmp cs:multi_line_outstanding,0
je no_multi_line ; if 0, no multi-line in process
jmp do_multi_line
;
no_multi_line:
;
call get_string_from_kbd ; fake a real 'get string' call
push_m <bp,ax>
mov bp,dx
mov ah,byte ptr ds:[bp+1] ; get length of string entered
cmp ah,0 ; do nothing if user just pressed RETURN
jne not_zerolen2
jmp short zero3
not_zerolen2:
cmp ah,1 ; is string only 1 char long?
jne not_zerolen
mov ah,byte ptr ds:[bp+2]
cmp ah,SEPARATOR ; and is that 1 char an ampersand?
jne not_zerolen ; forget it if so
mov byte ptr ds:[bp+1],0
mov byte ptr ds:[bp+2],CR ; else clear the ampersand
zero3:
pop_m <ax,bp>
call restore_flags
iret ; There's nowt for us to do
not_zerolen:
pop_m <ax,bp>
push ax
push bp
mov bp,dx
mov ah,ds:[bp+2] ; get 1st char in string
cmp ah,override ; is it the override character?
jne find_ab ; if not, proceed
mov byte ptr ds:[bp+2],' ' ; else, replace ~ with space
pop bp
pop ax
;
call restore_flags
iret ; and return to caller
;
find_ab:
;
pop bp
pop ax
find_ab2: ; Come here after expanding an alias,
; thus allowing nesting.
push ax ; Allow ESC to abort recursive aliases
push dx
special_key:
mov ah,6 ; is there a char waiting?
mov dl,0FFh
int 21h
jz no_break ; no key is waiting
cmp al,0
je special_key
cmp al,ESCAPE ; is key ESCAPE?
jne no_break
pop dx
pop ax
call restore_flags ; ESC pressed. Tidy up.
push bp
mov bp,dx
mov byte ptr ds:[bp+1],0 ; Clear the buffer, so passing DOS
mov byte ptr ds:[bp+3],CR ; an empty command string.
pop bp
iret
no_break:
pop dx
pop ax
; Before operating on user's string,
; remove any leading spaces.
call shift_left
; If the first 6 characters in the
; string are 'ALIAS 'then do requested
; command. If not, search table and
; replace string if required.
; 1st string at ds:si
push_m <si,ds,es,di,cx,ax>
mov si,dx
add si,2
mov ax,cs
mov es,ax
mov ax,offset cs:match
mov di,ax ; 2nd string at es:di
mov cx,6 ; compare 6 bytes
cld
repe cmpsb
je ab_found
;
mov si,dx ; if not found, try looking for upper
add si,2 ; case version too
mov di,offset cs:match_u_case
mov cx,6
repe cmpsb
je ab_found
;
jmp not_ab ; jump if alias command not typed
;
ab_found:
;
pop_m <ax,cx,di,es,ds,si>
; an alias command was typed, so find
; out what one it is, and act on it
push ax
push bp
mov bp,dx
mov ah,byte ptr ds:[bp+1] ; string must be 7 chars long
cmp ah,7
pop bp
pop ax
jnb length_correct
jmp bye
;
length_correct:
;
push ax
push bp
mov bp,dx
mov ah,byte ptr ds:[bp+8] ; get 8th char of string
or ah,00100000b ; force to lower case
mov cs:command_letter,ah ; save it
pop bp
pop ax
;
; the following list of CMP's may well
; be bad programming practice, but it
; is easier to follow than a jump
; table, and is shorter too!
cmp letter,'?'
jne x1
call ab_help
jmp bye
x1: cmp letter,'a'
jne x2
call ab_add
call ab_order
jmp bye
x2: cmp letter,'d'
jne x3
call ab_delete
call ab_order
jmp bye
x3: cmp letter,'l'
jne x4
call ab_order
call ab_list
jmp bye
x4: cmp letter,'w'
jne x5
call ab_order
call ab_write
jmp bye
x5: cmp letter,'r'
jne x6
call ab_read
jmp bye
x6: cmp letter,'c'
jne x7
call ab_colour
jmp bye
x7: cmp letter,'n'
jne x8
call ab_none
jmp bye
x8: cmp letter,'i'
jne x9
call ab_info
jmp bye
x9: cmp letter,'f'
jne xa
call ab_flush
jmp bye
xa: cmp letter,'p'
jne xb
call ab_prompt
jmp bye
xb: cmp letter,'g'
jne xc
call ab_global
jmp bye
xc: cmp letter,'s'
jne xd
call ab_show
jmp bye
xd: cmp letter,'b'
jne xe
call ab_buffer
jmp bye
xe: cmp letter,'h'
jne xf
call ab_hide
jmp bye
xf: cmp letter,'h' ; unused dummy. SPARE.
jne xg
call ab_hide
jmp bye
xg: cmp letter,'h' ; unused dummy. SPARE
jne xh
call ab_hide
jmp bye
xh: cmp letter,'z'
jne xi
jmp ab_zap
xi: call invalid_letter
bye: ; come back here if user says "No"
; when asked if sure about Zap
push bp
mov bp,dx
push ax ; save details before overwriting str,
; so they can be retrieved when this
; int handler is called again. Allows
; alias cmds to be recalled with F3.
mov al,ds:[bp+1]
mov byte ptr cs:kb_str_len,al ; save length of string
mov al,ds:[bp+2]
mov byte ptr cs:kb_str_ch1,al ; save 1st char
pop ax
mov byte ptr cs:do_kb_str,1 ; flag to say put back values
mov byte ptr ds:[bp+1],0 ; set length to 0 to stop ALIAS cmd
; being executed by DOS
mov byte ptr ds:[bp+2],CR ; put c/r terminator in buffer too
pop bp
;
call restore_flags
iret
;
not_ab:
;
pop_m <ax,cx,di,es,ds,si>
; No ALIAS command typed. Search
; table and substitute if necessary
cmp cs:[ab_status],0 ; don't substitute if aliases off
je back_to_dos
jmp turned_on
back_to_dos:
call restore_flags
iret
turned_on: ; aliases are not off so continue
;
mov byte ptr cs:nest_flag,0 ; set if expansion takes place
push bp
mov bp,dx
cmp byte ptr ds:[bp+1],0 ; get length of user's string
; if it's zero, abort.
;
pop bp
je too_long ; abort if it is
jmp length_ok ; otherwise OK to continue
too_long:
call copy_to_psp
jmp ok_to_cont2
length_ok: ; fill buffer with 0's
push_m <ax,es,di,cx>
cld
mov ax,cs
mov es,ax
mov al,0h
mov di,offset cs:buffer
mov cx,LHS_LEN
rep stosb
pop_m <cx,di,es,ax>
; Now put the string at ds:dx
; into the buffer,
; up to (but not including) the 1st
; space char
push_m <ax,bp,si,es,cx>
mov bp,0 ; set count to 0
mov si,dx
do_again:
mov ah,ds:[si+bp+2] ; get count'th char from user's string
cmp ah,SPACE ; is it a space
je buffer_filled ; jump if it is
cmp ah,CR ; is it CR (= end of string)
je buffer_filled ; jump as though space was found
or ah,00100000b ; force char to lower case as in table
mov cs:[buffer+bp],ah ; put string in buffer
inc bp ; increment counter
cmp bp,LHS_LEN ; all done?
jne do_again ; loop if not
;
buffer_filled:
;
; We've taken the first word in the
; string. Now take the remainder of the
; string and put it in the parameter
; buffer, for adding on to the replaced
; string after the alias has been
; substituted.
push_m <di,ax,si,bp>
mov di,offset cs:param_buff ; adr of buffer
param1:
mov ah,byte ptr ds:[si+bp+2] ; get next char from user
mov byte ptr cs:[di],ah ; put char in buffer and leave
; CR at end as terminator
cmp ah,CR
je param_done
inc di
inc si
jmp short param1
param_done:
pop_m <bp,si,ax,di>
pop_m <cx,es,si,bp,ax>
; user's string, padded with 0's, is in
; buffer, ready to compare to
; table entries.
push_m <ax,bx,ds,si,es,di,cx>
mov bh,1 ; count 30 comparisons
mov di,offset cs:ab_table ; es:di is the ab_table
find_match:
mov ax,cs ; ds:si is buffer
mov ds,ax
mov si,offset cs:buffer
mov ax,cs
mov es,ax
;
mov cx,LHS_LEN ; compare for 6 characters
repe cmpsb
jne oops
jmp match_found
oops:
inc bh ; no match found so loop again
cmp bh,TBL_LEN + 1
je no_luck
add di,RHS_LEN + 1 ; jump to next entry
add di,cx ; and skip over unchecked characters
jmp find_match ; from previous pass through loop
no_luck:
pop_m <cx,di,es,si,ds,bx,ax>
call copy_to_psp
jmp ok_to_cont2
match_found:
mov byte ptr cs:nest_flag,1 ; an expansion took place
mov cs:match_pos,di
pop_m <cx,di,es,si,ds,bx,ax>
; the position in ab_table at which
; the matching string starts, is now
; in match_pos.
; The string at cs:match_pos
; must be copied
; to ds:dx+2. must put match_len
; in ds:dx+1.
push ax
mov ax,cs:match_pos
mov cs:multi_start,ax ; set start address to match_pos
pop ax
do_multi_line:
; Although we have come here, if
; global commands are not set and
; the call was not from the DOS
; prompt, return to read keybd
; instead. This will make commands
; like DEBUG & DIR work properly,
; so that it will enter debug, pass
; control to the keyboard and then
; do a DIR after exiting debug. This
; assumes that global expansion is
; not set. If it is, the DIR gets
; passed to debug.
push_m <ax,bx,bp>
mov bp,sp
mov ax,ss:[bp+8]
mov bx,cs:command_cs
cmp ax,bx
jne not_from_prompt
mov ax,ss:[bp+6]
mov bx,cs:command_ip
cmp ax,bx
jne not_from_prompt
jmp ok_to_continue
not_from_prompt:
pop_m <bp,bx,ax>
cmp byte ptr cs:expand_from,1
je ok_to_cont2
jmp no_multi_line
ok_to_continue:
pop_m <bp,bx,ax>
ok_to_cont2:
mov cs:multi_len,0 ; length of string = 0
push_all
cld
push cs
pop ds
mov si,cs:multi_start ; lodsb works with ds:si
multi1:
lodsb ; get char from string
cmp al,0 ; end of string reached?
je null_found
cmp al,SEPARATOR ; multiple command separator?
je ampersand_found
mov bh,cs:multi_len ; inc length of string & get next char
inc bh
mov cs:multi_len,bh
jmp multi1
null_found: ; end of string found so put into ds:dx
pop_all
push ax
mov ax,cs:multi_start
mov cs:match_pos,ax
mov ah,cs:multi_len
mov cs:match_len,ah
pop ax
mov byte ptr cs:multi_line_outstanding,0
call subst ; put string from alias table into ds:dx
call expand_percents ; If we put any % signs into ds:dx
; buffer then replace with parameters.
call restore_flags
call echo
; We are done. However, instead of just
; IRETing, check to see if an expansion
; took place. If it did, go round and
; check again, to allow nesting.
cmp byte ptr cs:nest_flag,1
jne no_nest
jmp find_ab2
no_nest: ; If no expansion took place, don't need
; to go round again.
iret
ampersand_found:
; A multiple-command-line separator
; found. Set starting position to
; 1st char after the ampersand,
; so we know where to start from next
; time. Then set the flag so that
; we come straight here next time
; that the 'get string' interrupt
; gets called, to put the next part
; of the multi-command line into the
; kbd buffer.
pop_all
push ax
mov ax,cs:multi_start
mov cs:match_pos,ax
mov ah,cs:multi_len
mov cs:match_len,ah
pop ax
mov byte ptr cs:multi_line_outstanding,1
call subst ; Put string from alias table into ds:dx
call expand_percents ; Expand any percent characters that
; were copied from alias table by SUBST.
push ax
mov ah,0
mov al,cs:multi_len
add ax,cs:multi_start
inc ax
mov cs:multi_start,ax
pop ax
call echo
call restore_flags
iret
; -----------------------------------------------------------------------
; P R O C E D U R E S
; -----------------------------------------------------------------------
restore_flags proc ; restore flags register before iret
push ax
mov ax,cs:save_flags
push ax
popf
pop ax
ret
restore_flags endp
;
get_vpage proc ; get current video page into bh, so
; that we use the current video page
; for screen I/O.
push ax
push bx
push cx
push dx
push si
push di
mov ah,0fh
BIOS_VIDEO ; page is in bh
pop di
pop si
pop dx
pop cx
pop ax ; gets old BX without destroying new bh
mov bl,al ; restore old bl
pop ax ; restore old ax
ret
get_vpage endp
;
crlf proc ; display carriage return and linefeed
disp_ch CR
disp_ch LF
ret
crlf endp
;
are_you_sure proc ; asks user "Are you sure you want to?"
; Sets confirm to 1 if user hits Y or y,
; or sets to 0 otherwsie. All
push_all ; registers preserved.
mov bl,byte ptr cs:colour
mov si,offset cs:sure_msg
call disp_str_colour ; display message in current colour
sure1:
mov ah,8 ; get key (without echo) into al.
int 21h
cmp al,0 ; if it's a 2-byte code,
je sure1 ; then go round again.
or al,00100000b ; make character lower case
push_m <ax,bx,cx,si,di>
mov bl,cs:colour ; get current colour
call get_vpage ; current page into bh
mov cx,1 ; do it once
mov ah,9
BIOS_VIDEO ; echo Y or N to console in correct
; colour
pop_m <di,si,cx,bx,ax>
cmp al,'y' ; Y or y pressed?
jne not_y
mov byte ptr cs:confirm,1 ; set flag to show Y or y typed
jmp short sure_done
not_y: cmp al,'n'
jne sure1 ; get key again if not y or n
mov byte ptr cs:confirm,0 ; set flag to show Y or y not typed
sure_done:
pop_all
call crlf
push_m <si,di,cx,bx,ax>
mov ah,9
mov al,SPACE
mov bl,WHITE ; attrib
call get_vpage ; get vpage into bh
mov cx,1
BIOS_VIDEO
pop_m <ax,bx,cx,di,si>
ret
are_you_sure endp
;
shift_left proc ; Remove any leading spaces in the
; string at ds:dx+2. Adjust length of
; string in byte at ds:dx+1, to reflect
; the number of spaces removed.
push_all
mov ah,0 ; we only use al.
mov bp,dx ; start of func 0Ah's buffer
add bp,2 ; skip to 1st char of user's input
mov si,0 ; user si as a counter
shift1:
mov al,ds:[bp] ; get a char from user's string
cmp al,SPACE
jne not_a_space
inc si ; inc counter for no. of spaces found
inc bp ; point to next char in string
jmp short shift1 ; and round we go again
not_a_space: ; ah holds no. of leading spaces found
cmp si,0 ; any spaces found?
je shift_done ; we're finished if none found
mov bp,dx ; point to start of string again
add bp,2
add bp,si ; jump over spaces to 1st non-space char
shift2:
mov al,ds:[bp] ; get char
sub bp,si ; adjust bp
mov byte ptr ds:[bp],al ; move char back, Can't have [bp-si],
; hence the above subtraction
add bp,si ; adjust bp back again
inc bp
cmp al,CR ; have we just shifted a CR?
jne shift2 ; no, so round again
mov bp,dx ; CR shifted, so we're done.
inc bp ; point to length counter
mov al,ds:[bp] ; get it
sub ax,si ; subtract no. of leading spaces. ah is
; zero, so ax is really al.
mov byte ptr ds:[bp],al ; and replace new byte
shift_done:
pop_all
ret
shift_left endp
;
restore_buffer proc
push bp ; restore the buffer from the previous
push ax ; use of this function, so that alias
mov bp,dx ; commands can be recalled with F3.
mov al,cs:kb_str_len
mov byte ptr ds:[bp+1],al
mov al,cs:kb_str_ch1
mov byte ptr ds:[bp+2],al
pop ax
pop bp
ret
restore_buffer endp
;
copy_to_psp proc
; although the command is not an alias
; command, don't just iret. Instead,
; copy the string to a spare part of
; memory, and pretend that that area
; of memory contains a valid alias.
; That way, the DOS command can have
; ampersands in it, which will be
; treated properly.
;
; The spare part of memory used is the
; PSP that remains after installation,
; at address CS:5Ch.
push_m <es,di,si,bp,cx>
cld
mov si,dx
add si,2 ; from ds:si = ds:dx+2
push cs
pop es
mov di,5ch ; to es:di = cs:5ch
mov bp,dx
mov cl,byte ptr ds:[bp+1]
mov ch,0 ; copy correct number of bytes
rep movsb
mov byte ptr es:[di],0 ; put null at end
pop_m <cx,bp,si,di,es>
;
mov cs:match_pos,5ch
mov cs:multi_start,5ch
mov byte ptr cs:multi_line_outstanding,0
ret
copy_to_psp endp
;
ab_buffer proc ;Display the DOSEDIT buffer.
push_all
mov byte ptr cs:list_count,0 ; count no of lines displayed
call get_lines
mov si,word ptr cs:cmdold ; get adr of 1st byte of oldest cmd
mov bp,word ptr cs:cmdpnt ; get adr of 1st byte of current cmd
dec bp ; prevent double crlf after listing
buf_top:
mov bl,byte ptr cs:colour ; get current ALIAS colour
call crlf
inc byte ptr cs:list_count
push ax
mov ah,byte ptr cs:page_len
cmp byte ptr cs:list_count,ah
pop ax
jne scr_not_full
call list_pause ; Press Any Key to Continue
scr_not_full:
push_all
call disp_str_colour ; show string on screen
pop_all
get_again:
mov ah,byte ptr cs:[si] ; get 1st char of command again
cmp ah,0 ; end of command?
je new_command ; yes...
call cmdinc ; no, so inc pointer
jmp short get_again ; and keep looking
new_command:
cmp si,bp ; are all commands printed?
je buf_done
call cmdinc ; point to start of next command
jmp short buf_top ; and start all over again
buf_done:
pop_all
disp_ch LF
push_m <di,si,cx,bx,ax> ; Display a white space.
mov ah,9
mov al,SPACE
mov bl,WHITE ; attrib
call get_vpage ; video page into bh
mov cx,1
bios_video
pop_m <ax,bx,cx,si,di>
ret
ab_buffer endp
;
subst proc
; This procedure gets a string which
; starts at cs:match_pos with length
; cs:match_len, and puts it in the
; buffer which is set up for a string
; by a routine that calls DOS
; function 0Ah. The string will be
; placed in ram starting at ds:dx+2.
; Its length will get put in ds:dx+1
; and a carriage return gets put at
; the end of the string, though this
; is not included in the char count.
push_all
push cs
pop es ; source segment
mov bp,dx ; destination segment
mov bl,byte ptr ds:[bp] ; get length of buffer
mov bh,0 ; counter
add bp,2 ; destination offset
mov si,cs:match_pos ; start of string
mov cl,cs:match_len ; length
cmp cl,0 ; is string empty (ie user just pressed
; RETURN)
jne keep_on
mov byte ptr ds:[bp],CR ; put CR at end(!) of empty string
jmp short subst_done
keep_on:
mov al,es:[si] ; get char from string
mov byte ptr ds:[bp],al ; and put it in place
dec cl ; count down till whole string copied
inc si ; inc source pointer
inc bp ; inc dest pointer
inc bh
cmp cl,0 ; are we done?
je stuffed
cmp bh,bl ; or is buffer full?
je stuffed
jmp short keep_on
stuffed:
mov byte ptr ds:[bp],CR ; put CR at end
push bp ; set length
push ax
mov ah,cs:match_len
mov bp,dx
add bp,1
mov ds:[bp],ah
pop ax
pop bp
pop_all
subst_done:
ret
subst endp
;
expand_percents proc
; This proc takes the contents of the
; buffer at ds:dx, which SUBST has
; copied an alias into, and expands any
; %n characters into the correct strings
; taken from param_buff.
; Percent params are handled by Alias in
; the same way as DOS batch files,except
; that there is no %0 implementation,and
; there is a %*, which is the whole
; parameter buffer.
push_all
expand_vtop:
mov si,dx ; point to start of ds:dx buffer
inc si
expand_top:
inc si
mov al,byte ptr ds:[si] ; get char from buffer
cmp al,CR ; are we at the end of the buffer?
jne ok
jmp expand_done
ok:
cmp al,'%' ; is the char a percent?
je percent_found ; jump if so
jmp short expand_top
percent_found:
mov byte ptr cs:star_flag,0
; a percent was found in ds:dx buffer.
; It's only valid and expandable if
; followed by a digit.
; Check si+1, which must be a digit
; If we find %*, change it to %1, but
; set an internal flag.
cmp byte ptr ds:[si+1],'*'
jne expand12
mov byte ptr ds:[si+1],'1'
mov byte ptr cs:star_flag,1
expand12:
cmp byte ptr ds:[si+1],'1'
jb expand_top
cmp byte ptr ds:[si+1],'9'
ja expand_top
; SI is pointing to a percent char,
; which is the start of a valid
; parameter sequence.
mov cl,byte ptr ds:[si+1] ; get the parameter
sub cl,'0' ; convert to binary digit
; Before we copy parameter in, check
; that a) it exists, and b) that it will
; fit into the buffer.
; Count the number of parameters, to see
; if cl exists.
push bp
push bx
mov bp,offset cs:param_buff
mov bh,0
counter_top:
mov bl,byte ptr cs:[bp]
cmp bl,CR
je counter_done
cmp bl,SPACE
je param_found
inc bp
jmp short counter_top
param_found:
inc bh
inc bp
jmp short counter_top
counter_done:
cmp bh,cl ; did we find enough parameters?
pop bx
pop bp
jae enough_params
; There are not enough params to expand
; the % sign currently pointed to by si.
; Delete % and the digit. This is the
; way that DOS handles this situation.
push bp
mov bp,si
call close_up_buffer ; Delete char at bp, and amend length
call close_up_buffer
pop bp
dec si ; compensate for expand_top's inc si
jmp short expand_top
enough_params:
; parameter cl exists. If it will fit,
; it can be copied in, but we don't
; yet know if it will fit...
; find out if parameter cl will fit.
; dx = length of buffer, dx+1 holds
; current number of chars in buffer.
; If length of parameter
; <= ([dx]-[dx+1]-1) then all is well.
; First, get length of parameter
mov bp,offset cs:param_buff
mov bh,0
expand5:
mov bl,byte ptr cs:[bp] ; get char from param_buff
cmp bl,SPACE
je expand4
inc bp
jmp short expand5
expand4:
inc bp
inc bh
cmp bh,cl
jne expand5
; bp contains start of parameter.
; Count till next space, or CR, found.
mov bh,0
mov ax,bp ; preserve start of parameter
expand7:
mov bl, byte ptr cs:[bp]
cmp byte ptr cs:star_flag,1
je expand14 ; don't stop at spaces if %*
cmp bl,SPACE
je expand6
expand14:
cmp bl,CR
je expand6
inc bp
inc bh
jmp short expand7
expand6:
; bh contains length of parameter cl
mov di,dx
mov ch,byte ptr ds:[di] ; ch = length of buffer,
mov cl,byte ptr ds:[di+1] ; cl = chars in buffer
; Note: This is not the same as
; mov cx,word ptr ds:[di], as that would
; leave ch and cl transposed.
sub ch,cl
dec ch ; ch now contains space left in buffer
cmp bh,ch
jna expand_fits ; jump if not above.
; Can't use jle, cos that's for
; signed numbers.
call no_fit ; warn user that it doesn't fit.
jmp expand_done ; parameter will not fit, so quit.
expand_fits: ; parameter will fit so copy it
; copy parameter starting at ds:[ax] and
; finishing with SPACE or CR into
; ds:dx buffer. Delete the % and the
; following 2 chars. Amend length.
mov di,si
mov si,ax ; source is now si, dest is di
; First, close up the gap.
; Delete char at di, di+1 and di+2,
; and amend length.
push bp
mov bp,di
call close_up_buffer ; delete the %
call close_up_buffer ; delete the digit
pop bp
; now copy in the string
expand9:
mov al,byte ptr cs:[si] ; get char
cmp byte ptr cs:star_flag,1
je expand15 ; don't stop at spaces if %*
cmp al,SPACE
je expand11
expand15:
cmp al,CR
je expand11
call put_in_dsdx ; insert al into ds:dx buffer at [di].
; di returns pointing at new char.
inc si
jmp short expand9
expand11:
jmp expand_vtop ; Every time, we start parsing from
; dx+2, rather than from where we left
; off last time. This is not the most
; efficient coding!
expand_done:
pop_all ; Finished proc. Params substituted.
ret
expand_percents endp
;
close_up_buffer proc
; delete the char at [bp] in a buffer,
; whose length is at dx+1. Amend length.
push bp
push ax
inc bp ; point past the char to delete
close1:
mov al,ds:[bp] ; get a char
mov byte ptr ds:[bp-1], al ; shift the char left
cmp al,CR ; are we done
je closed
inc bp
jmp short close1
closed:
; char is deleted. Amend length.
mov bp,dx
inc bp ; point to length
mov al,byte ptr ds:[bp] ; get length
dec al ; decrement it
mov byte ptr ds:[bp],al ; and write new value back
pop ax
pop bp
ret
close_up_buffer endp
;
put_in_dsdx proc ; insert al into ds:dx buffer at ds:[di]
; di returns pointing at new char
; Update length at dx+1
push si
push ax
push bx
mov si,dx ; point to start of buffer
inc si ; point to length
mov bl,byte ptr ds:[si] ; get length
inc bl
mov byte ptr ds:[si],bl ; update length while we're here
dec bl
mov bh,0
add si,bx ; point to terminating CR
inc si
inc si
put_in:
dec si
mov ah,byte ptr ds:[si] ; get char from string
mov byte ptr ds:[si+1],ah ; shift it right
cmp si,di ; are we done?
jne put_in
mov byte ptr ds:[di],al ; insert char in newly created space
inc di
pop bx
pop ax
pop si
ret
put_in_dsdx endp
;
no_fit proc ; The string can't be expanded, cos it
; will end up longer than the ds:dx
; buffer provided for it. Clear the
; buffer and display a warning message.
mov bp,dx
mov byte ptr ds:[bp+1],0 ; set length to 0
mov byte ptr ds:[bp+2],CR ; add a CR on end
mov bl,cs:colour
mov si,offset cs:no_fit_msg
call disp_str_colour
ret
no_fit endp
;
echo proc
; This routine is called once the
; aliased string has been assembled
; at ds:dx+2, and immediately before
; the IRET. If echo is turned on,
; we echo the string at ds:dx+2 to the
; console, in the current colour, and
; enclosed in square brackets.
; This echo only occurs if the string
; was placed at ds:dx+2 because an alias
; was found in the table. If no
; substitution ocurred, there's no echo.
cmp byte ptr cs:echo_status,1 ; do we want echo?
je echo_wanted
jmp not_required
echo_wanted:
call crlf
push_all
mov si,offset cs:left_sq_br ; display a '[' in current colour
mov bl,cs:colour
call disp_str_colour
pop_all
push_all
mov si,dx ; start of string
add si,2
mov bl,cs:colour ; screen attribute to use
mov bp,dx
mov al,ds:[bp+1] ; get length of string
mov ah,0
add bp,ax ; point to CR at end of string
add bp,2 ; skip first 2 bytes
mov byte ptr ds:[bp],0 ; change CR to a 0 for use with proc
push_all
mov byte ptr cs:echo_flag,1 ; 'cos string is in ds
call disp_str_colour ; display 0-terminated string
mov byte ptr cs:echo_flag,0 ; back to cs for other procs to use
pop_all
mov byte ptr ds:[bp],CR ; put the CR back
pop_all
push_all
mov si,offset cs:rght_sq_br ; display a ']' in current colour
mov bl,cs:colour
call disp_str_colour
pop_all
disp_ch LF ; ensure DOS default colour returns to
; white.
not_required:
ret
echo endp
;
ab_none proc ; ALIAS N turns off aliases
mov byte ptr cs:ab_status,0
call crlf
ret
ab_none endp
;
ab_info proc ; ALIAS I displays info
push_m <dx,ds,ax> ; Display version number
mov ax,cs
mov ds,ax
push_m <bx,si>
mov si,offset cs:version
mov bl,cs:colour
call disp_str_colour
pop_m <si,bx>
pop_m <ax,ds,dx>
;
push_all
cmp byte ptr cs:ab_status,0 ; don't display show/hide if off
je info2
cmp byte ptr cs:echo_status,0 ; display show or hide
je info1
mov si,offset cs:msg_show
mov bl,byte ptr cs:colour
call disp_str_colour
jmp info2
info1:
mov si,offset cs:msg_hide
mov bl,byte ptr cs:colour
call disp_str_colour
info2: ; display on/off/global
cmp byte ptr cs:ab_status,0
je info3
cmp byte ptr cs:expand_from,0
je info4
mov si,offset cs:msg_global
mov bl,byte ptr cs:colour
call disp_str_colour
jmp info6
info4:
mov si,offset cs:msg_prompt
mov bl,byte ptr cs:colour
call disp_str_colour
jmp info6
info3:
mov si,offset cs:msg_off
mov bl,byte ptr cs:colour
call disp_str_colour
info6:
pop_all
call disp_def_fn ; display full path of default file
call alias_count ; display no of aliases, + table size
push_m <si,di,cx,bx,ax> ; Display a white space.
mov ah,9
mov al,SPACE
mov bl,WHITE ; attrib
call get_vpage ; video page into bh
mov cx,1
bios_video
pop_m <ax,bx,cx,di,si>
ret
ab_info endp
;
disp_def_fn proc ; Display the default file name that
; will be used in ALIAS W commands.
; If the def_dir string is empty,
; display default_fn. If def_dir is
; not empty, it is the path and file
; that was loaded at install time, so
; it's the one to display.
push_all
mov si,offset cs:def_fn_msg
mov bl,byte ptr cs:colour
call disp_str_colour
mov si,offset cs:default_fn ; use the non-pathed file?
mov al,byte ptr cs:[def_dir] ; get 1st byte of pathed string
cmp al,0 ; is it empty?
je use_non ; yes, so stay as we are
mov si,offset cs:defdir_hdr ; pathed string exists so use instead.
use_non:
mov bl,byte ptr cs:colour
call disp_str_colour
pop_all
ret
disp_def_fn endp
;
alias_count proc ; Called by ALIAS I command to display
; the number of defined/undefined
; aliases.
call count_aliases ; count entries in table and plug the
; numbers into the string about to be
; displayed.
push_all
mov si,offset cs:count_msg ; display the message
mov bl, byte ptr cs:colour
call disp_str_colour
pop_all
ret
alias_count endp
;
count_aliases proc
push_m <ax,bx,cx,dx,bp>
mov ax,0 ; count full entries in ax
mov bx,0 ; count total table entries in bx
mov bp,offset cs:ab_table ; start of the table
count_top:
mov dh,byte ptr cs:[bp] ; get 1st char from table entry
cmp dh,0F0h
je count_done
cmp dh,0 ; is entry full?
je count_empty ; no, then it's empty!
inc ax ; full entries
count_empty:
inc bx ; total entries
add bp,RHS_LEN + LHS_LEN + 1 ; point to next entry
jmp short count_top
count_done:
; ax and bx contain totals. Now plug
; them in.
aam ; put digits of ax into ah and al
add ax,3030h ; convert to ascii
mov bp,offset cs:count_msg1
mov byte ptr cs:[bp],ah
mov byte ptr cs:[bp+1],al
mov ax,bx ; Now do the second number
aam
add ax,3030h
mov bp,offset cs:count_msg2
mov byte ptr cs:[bp],ah
mov byte ptr cs:[bp+1],al
pop_m <bp,dx,cx,bx,ax>
ret
count_aliases endp
;
ab_prompt proc
mov byte ptr cs:expand_from,0 ; expand from dos prompt
mov byte ptr cs:ab_status,1 ; turn on
call crlf
ret
ab_prompt endp
;
ab_global proc
mov byte ptr cs:expand_from,1 ; expand globally
mov byte ptr cs:ab_status,1 ; turn on
call crlf
ret
ab_global endp
;
ab_help proc ; ALIAS ? gives help
push_m <bx,si,dx,ds,ax>
mov bl,cs:colour
mov si,offset cs:help_text
call disp_str_colour
pop_m <ax,ds,dx,si,bx>
ret
ab_help endp
;
ab_add proc ; ALIAS A <arg> <string>
; Before doing anything else,check that
; user left a space between ALIAS A and
; the arg, or prog will hang. ie,
; abort if [dx+9] is not a space.
push_m <ax,bp>
mov bp,dx
mov ah,byte ptr ds:[bp+9] ; get the char between ALIAS L and arg
cmp ah,' ' ; is it a space
pop_m <bp,ax>
je ok_space3 ; continue if ok. Can't write jne 'cos
; out of range.
call syntax_error ; error - no action taken
jmp add_err ; if not a space, abort A command
ok_space3:
call to_lower ; Make the LHS part of the alias lower
; case. Leave the RHS part as it is,
; because user may want to specify
; a case-specific alias, for example
; as command-line options on MS C.
push_m <ax,bx,cx,dx,bp,si>
mov si,0 ; count length of arg
mov bp,dx
add bp,10 ; point to arg
add2:
mov ah,ds:[bp+si] ; get arg character
; is it c/r? If so, no string was
; typed so abort
cmp ah,CR
jne not_cr
pop_m <si,bp,dx,cx,bx,ax>
call syntax_error
jmp add_err ; abort
not_cr:
cmp ah,' ' ; is it a space?
je add1
cmp si,LHS_LEN ; or have we done 6 chars?
je add1
inc si ; no. point to next char
jmp add2
add1:
mov bx,si
mov cs:arg_end,bl ; arg_end is length of arg
;
mov si,0
mov bp,dx
add bp,10 ; point to 1st char of lhs
mov al,cs:arg_end
mov ah,0
add bp,ax
; bp should now point to a space, and
; incrementing it will point to the
; start of the rhs. But this will not
; be so if the lhs was > 6 chars, so
; so we may need to add more to bp.
add11:
cmp byte ptr ds:[bp],SPACE ; are we ok?
je add10 ; yes, so point to rhs and we're ok
inc bp
jmp short add11
add10:
inc bp
add3:
mov ah,ds:[bp+si]
cmp ah,CR ; end of string
je add4
cmp si,RHS_LEN ; truncate if necessary
je add4
inc si
jmp add3
add4:
mov bx,si
mov cs:str_end,bl
; Arg starts at dx+10, length arg_end.
; Str starts at dx+11+arg_end,
; with length str_end
pop_m <si,bp,dx,cx,bx,ax>
;
cmp byte ptr cs:arg_end,LHS_LEN
jbe add6 ; must be < 6 chars
jmp add_err ; else give error and exit.
; Actually, string has been truncated
; above, so it should never fail here.
add6:
cmp byte ptr cs:str_end,RHS_LEN ; Ensure length of rhs string is OK.
; It should be, cos it was truncated
; by the routines above.
jbe add7
jmp add_err
add7:
push_m <es,di,cx,ax> ; fill 6-char buffer with 0's
cld
mov ax,cs
mov es,ax
mov al,0
mov di,offset cs:buffer2
mov cx,LHS_LEN
rep stosb
pop_m <ax,cx,di,es>
; Put arg into buffer.
push_m <ax,cx,dx,es,ds,di,si>
cld
mov ax,cs
mov si,dx
add si,10 ; copy from ds:dx+10
mov es,ax
mov di,offset cs:buffer2 ; copy to buffer
mov cl,cs:arg_end ; no of bytes to copy
mov ch,0
rep movsb
pop_m <si,di,ds,es,dx,cx,ax>
;
; Now scan buffer vs table,
; to ensure that
; arg doesn't already exist
push_m <ax,bx,cx,ds,es,di,si>
mov bh,1 ; count for up to 30 comparisons
mov di,offset cs:ab_table
scan:
mov ax,cs
mov es,ax
mov ds,ax
mov si,offset cs:buffer2
mov cx,LHS_LEN
cld
repe cmpsb
jne scan2
jmp already_in_table
scan2: ; no match, so loop again
inc bh
cmp bh,TBL_LEN + 1
je not_in_table
add di,RHS_LEN + 1
add di,cx
jmp scan
already_in_table: ; can't add, cos it already exists
pop_m <si,di,es,ds,cx,bx,ax>
call exist_err ; display error msg
ret
not_in_table:
pop_m <si,di,es,ds,cx,bx,ax>
; we have a string that does not
; already exist. Now find an empty
; table entry
push_m <ax,bx,bp>
mov bh,1 ; do up to 30 comparisons
mov bp,offset cs:ab_table ; start of table
keep_looking:
mov ah,cs:[bp] ; get 1st char of arg
cmp ah,0 ; if char is 0 then space is free
je entry_spare
add bh,1 ; inc counter
add bp,LHS_LEN+RHS_LEN+1
cmp bh,TBL_LEN + 1 ; all done?
jne keep_looking ; no , so round again
pop_m <bp,bx,ax> ; no space, so quit
call table_full ; and display error message
ret
entry_spare:
mov cs:spare,bp ; 1st byte of table entry
pop_m <bp,bx,ax>
;
; fill table from spare for 77
; bytes, with 0
push_m <di,es,cx,ax>
cld
mov ax,cs
mov es,ax
mov di,cs:spare
mov cx,LHS_LEN + RHS_LEN + 1
mov al,0
rep stosb
pop_m <ax,cx,es,di>
;
push_m <ax,cx,di,si,es>
mov ax,dx
add ax,10
mov si,ax ; copy arg from ds:di
mov ax,cs
mov es,ax ; to es:di
mov di,cs:spare
mov ch,0
mov cl,cs:arg_end
rep movsb
;
mov ax,dx
add ax,10
mov bh,0
mov bl,cs:arg_end
add ax,bx
mov si,ax ; copy string from ds:si.
; SI currently points to the space
; before the rhs in the user's string.
; However, if the user entered an lhs
; that was too long we need to skip over
; those extra chars that are here.
add14:
cmp byte ptr ds:[si],SPACE ; are we in the right place
je add12 ; yes, then carry on
inc si ; else point to next char and try again
jmp short add14
add12:
inc si
mov ax,cs
mov es,ax ; to es:di
mov di,cs:spare
add di,LHS_LEN ; copy to string, not arg
mov ch,0
mov cl,cs:str_end ; no of chars to copy
rep movsb
;
pop_m <es,si,di,cx,ax>
add5:
call crlf
add_err:
ret
ab_add endp
;
table_full proc ; display 'table full' msg
push_all
mov bl,cs:colour
mov si,offset cs:table_full_msg
call disp_str_colour
pop_all
ret
table_full endp
;
ab_colour proc
call crlf
push_all
mov bl,cs:colour
mov byte ptr cs:old_col,bl ; save current colour in case of ESC
colour_top:
mov bl,cs:colour ; get current colour
mov si,offset cs:colour_msg
call disp_str_colour
get_colour_key:
mov ah,8 ; get key. no echo
int 21h
cmp al,0 ; 2-byte code?
je get_colour_key ; loop again if yes
;
cmp al,32 ; space character?
jne colour1
cmp byte ptr cs:colour,15 ; if colour = 15, reset to 1
jne colour2
mov byte ptr cs:colour,1
jmp colour_top
colour2:
inc byte ptr cs:colour
jmp colour_top
colour1: ; not a space. try for cr
cmp al,13
je colour3 ; jmp if cr.
cmp al,27 ; ESC?
jne get_colour_key ; get char again if not.
mov bl,cs:old_col ; ESC, so get old colour
mov byte ptr cs:colour,bl ; and make it the current colour
colour3:
pop_all
disp_ch CR ; all done. move crsr to start of line
push_all
mov al,32 ; display a line of spaces over line
mov bl,WHITE
mov bh,0
mov cx,75
mov ah,9
bios_video
pop_all
disp_ch CR ; put crsr at start of line again
ret
ab_colour endp
;
ab_show proc
mov byte ptr cs:echo_status,1
call crlf
ret
ab_show endp
;
ab_hide proc
mov byte ptr cs:echo_status,0
call crlf
ret
ab_hide endp
;
ab_delete proc ; ALIAS D <arg> deletes an entry
push_m <ax,bx,cx,dx,es,ds,si,di,bp>
mov bp,dx
mov ah,byte ptr ds:[bp+1] ; get length of string
cmp ah,7 ; if just ALIAS D typed...
je not_there ; ...then do nothing
; Before doing anything else,check that
; user left a space between ALIAS D and
; the arg, or prog will hang. ie,
; abort if [dx+9] is not a space.
push_m <ax,bp>
mov bp,dx
mov ah,byte ptr ds:[bp+9] ; get the char between ALIAS D and arg
cmp ah,' ' ; is it a space
pop_m <bp,ax>
je ok_space2 ; continue if ok. Can't write jne 'cos
; out of range.
jmp not_there ; if not a space, abort D command
ok_space2:
sub ah,8 ; arg is at dx+10 with len arg_end
mov cs:arg_end,ah
; fill buffer with 0's
mov ax,cs
mov es,ax
mov al,0
mov di,offset cs:buffer2
mov cx,LHS_LEN
cld
rep stosb
call copy_to_buffer2 ; copy arg into buffer
; now look through table. If arg
; exists, delete it.
mov bh,1 ; do up to 30 comparisons
mov di,offset cs:ab_table
not_there_yet:
mov ax,cs
mov es,ax
mov ds,ax
mov si,offset cs:buffer2
mov cx,LHS_LEN
cld
repe cmpsb
jne still_not_there
jmp got_it
still_not_there:
inc bh
cmp bh,TBL_LEN + 1
je not_there
add di,RHS_LEN + 1
add di,cx
jmp not_there_yet
got_it: ; di holds start of table
; entry so delete it
sub di,LHS_LEN
mov byte ptr es:[di],0 ; set 1st char to 0, = deleted
pop_m <bp,di,si,ds,es,dx,cx,bx,ax>
call crlf
ret
not_there:
pop_m <bp,di,si,ds,es,dx,cx,bx,ax>
call not_found ; show error cos entry doesn't exist
ret
;
ab_delete endp
;
ab_flush proc ; ALIAS F wipes entire table.
call are_you_sure ; ask user to confirm
cmp byte ptr cs:confirm,1 ; is user sure?
jne flush_done ; jump if no
push_m <di,es,cx,ax>
mov ax,cs
mov es,ax
mov di,offset cs:ab_table
mov al,0
mov cx,(RHS_LEN + LHS_LEN + 1) * TBL_LEN
rep stosb ; Fill entire table with 0's. Don't
pop_m <ax,cx,es,di> ; erase the bytes before the actual
; data, as these hold other bits of
; info that get saved with the table.
flush_done:
ret
ab_flush endp
;
ab_list proc ; ALIAS L lists the whole table.
; ALIAS L <arg> lists specified entry
; Note: the search routines used here
; are direct copies of the ones from
; the D command. Should really be put
; into a proc to save space.
call get_lines ; Set byte at cs:page_len to no. of
; lines that screen can display.
push_m <bp,ax>
mov bp,dx
mov ah,byte ptr ds:[bp+1] ; get length of string into ah
cmp ah,7 ; just ALIAS L typed?
pop_m <ax,bp>
jne list_single ; if not, list a single entry
jmp list_all ; If just ALIAS L, goto list_all
list_single:
; search table for specified entry..
; and list it if it exists.
; Before doing anything else,check that
; user left a space between ALIAS L and
; the arg, or prog will hang. ie,
; abort if [dx+9] is not a space.
push_m <ax,bp>
mov bp,dx
mov ah,byte ptr ds:[bp+9] ; get the char between ALIAS L and arg
cmp ah,' ' ; is it a space
pop_m <bp,ax>
je ok_space ; continue if ok. Can't write jne 'cos
; out of range.
call syntax_error
jmp list4 ; if not a space, abort L command
ok_space:
push_m <ax,bx,cx,dx,es,ds,si,di,bp>
mov bp,dx
mov ah,byte ptr ds:[bp+1] ; get length of string into ah
sub ah,8
mov cs:arg_end,ah ; the arg specified in cmd line is
; at dx+10, with length arg_end
; fill buffer with 0's
mov ax,cs
mov es,ax
mov al,0
mov di,offset cs:buffer2
mov cx,LHS_LEN
cld
rep stosb
call copy_to_buffer2 ; copy string to buffer
; now look through table. If arg
; exists, list it.
mov bh,1 ; do up to 30 comparisons
mov di,offset cs:ab_table
list_not_there_yet:
mov ax,cs
mov es,ax
mov ds,ax
mov si,offset cs:buffer2
mov cx,LHS_LEN
cld
repe cmpsb
jne list_still_not_there
jmp list_got_it
list_still_not_there:
inc bh
cmp bh,TBL_LEN + 1
je list_not_there
add di,RHS_LEN + 1
add di,cx
jmp list_not_there_yet
list_got_it: ; di holds start of table entry.
sub di,LHS_LEN ; move to start of entry
call crlf ; move crsr below DOS prompt line
call crlf ; and go down a line
call list_an_entry ; list it in current colour
pop_m <bp,di,si,ds,es,dx,cx,bx,ax>
jmp list4
list_not_there:
pop_m <bp,di,si,ds,es,dx,cx,bx,ax>
call not_found ; display error message
jmp list4 ; end of selective list routine
list_all: ; list whole table
mov byte ptr cs:list_count,0 ; line counter
push_m <di,ds,dx,cx,bx,ax>
call crlf
call crlf
mov bh,1 ; count 30 loops through table
mov di,offset cs:ab_table ; point to start of table
list1:
mov ah,cs:[di] ; get 1st char of arg
cmp ah,0 ; is entry empty?
jne not_empty
jmp list2 ; jump if so
not_empty:
inc byte ptr cs:list_count
push ax
mov ah,byte ptr cs:page_len
cmp byte ptr cs:list_count,ah
pop ax
jne page_not_full
call list_pause ; Press Any Key to Continue
page_not_full:
call list_an_entry ; list current entry in current colour
list2: ; ..unless current table entry is empty
inc bh ; counter for no of entries
cmp bh,TBL_LEN + 1 ; have we seen all the table
je list3 ; all done if yes
add di,LHS_LEN + RHS_LEN + 1 ; else point to next entry
jmp list1 ; and do it all again
list3:
pop_m <ax,bx,cx,dx,ds,di>
list4:
; Write a white space, for BIOS func 0Eh
; to use as reference for new attrib.
call crlf
push_m <cx,bx,ax,di,si>
mov ah,9
mov al,SPACE
mov bl,WHITE ; attrib
call get_vpage ; video page into bh
mov cx,1
bios_video
pop_m <si,di,ax,bx,cx>
ret
ab_list endp
;
not_found proc ; Display error message if the subject
; of an ALIAS L <arg> is not found.
push_all
mov bl,byte ptr cs:colour
mov si,offset cs:err_nfound
call disp_str_colour
pop_all
ret
not_found endp
;
exist_err proc ; Display error message if the subject
; of an ALIAS A already exists.
push_all
mov bl,byte ptr cs:colour
mov si,offset cs:exist_msg
call disp_str_colour
pop_all
ret
exist_err endp
;
get_lines proc
push ax ; Set page_len to no. of lines on scrn,
push ds ; so listings can pause when necessary.
mov ax,40h
mov ds,ax
mov ah,byte ptr ds:[84h] ; get DOS's screen length (in lines)
pop ds
cmp ah,0
je not_really_0
jmp short length_set
not_really_0:
mov byte ptr cs:page_len,25 ; If byte is 0, length is 25. That's
jmp short length_set_2 ; the rule, according to DOS books.
length_set:
mov byte ptr cs:page_len,ah
length_set_2:
pop ax ; page_length is now set.
ret
get_lines endp
;
list_pause proc
; Display a Press Any Key to Cont msg
push_all
mov byte ptr cs:list_count,0 ; clear the line counter
mov bl,byte ptr cs:colour
mov si,offset cs:press_msg
call disp_str_colour ; display message in current colour
pause1:
mov ah,8 ; get key (without echo) into al.
int 21h
cmp al,0 ; if it's a 2-byte code,
je pause1 ; then go round again.
; Cover the message with some spaces
disp_ch CR
push_all
mov al,SPACE
mov ah,09
mov bl,WHITE
mov cx,35
BIOS_VIDEO
pop_all
disp_ch CR
push_m <di,si,cx,bx,ax> ; avoid colour inheritance bug
mov ah,9
mov al,SPACE
mov bl,WHITE ; attrib
call get_vpage ; video page into bh
mov cx,1
bios_video
pop_m <ax,bx,cx,si,di>
pop_all
ret
list_pause endp
;
copy_to_buffer2 proc
; copy arg into buffer. used by L and D
mov ax,cs
mov si,dx
add si,10
mov es,ax
mov di,offset cs:buffer2
mov cl,cs:arg_end
mov ch,0
cx_not_zero:
cld
movsb ; copy ds:si to es:di
; don't use rep prefix cos we need
; to force chars to lower case when
; copied.
push ax
dec di ; put it where it was before the movsb
mov al,byte ptr es:[di] ; get the byte just copied
or al,00100000b ; make character lower case
mov byte ptr es:[di],al ; and put it back
inc di ; and put di back too
pop ax
dec cx ; dec counter
cmp cx,0
jne cx_not_zero
ret
copy_to_buffer2 endp
;
ab_order proc ; Sort the abbreviation table (in RAM)
; so that LHS entries are in ascending
; alphabetical order.
; Method used is a bubble sort.
; This proc is not called explicitly by
; the user. It is called automatically
; before a LIST or WRITE, and after a
; DELETE or ADD command is processed.
push_all
sort1:
mov byte ptr cs:sort_counter,0 ; count no. of swaps
mov word ptr cs:sort_pointer,offset cs:ab_table ; pointer into data
mov byte ptr cs:sort_entries,TBL_LEN ; no of entries
sort2:
cmp byte ptr cs:sort_entries,1 ; are we pointing at the last entry?
ja sort3 ; no
cmp byte ptr cs:sort_counter,0 ; We've finished a pass through the
; data. If there were no swaps, we
; are sorted.
je sorted
jmp sort1
sort3:
call sort_compare ; compare string at pointer with the
; following one and set swap_flag = 1
; if swap needed, else 0
cmp byte ptr cs:swap_flag,1 ; swap needed?
jne sort4 ; no
call sort_swap ; swap
inc byte ptr cs:sort_counter ; count swaps needed during the pass
sort4:
add word ptr cs:sort_pointer,LHS_LEN + RHS_LEN +1 ;point to next str
dec byte ptr cs:sort_entries ; see how far we've got to go
jmp sort2
sorted:
pop_all
ret
ab_order endp
;
sort_compare proc ; compare alphabetically the string
; at sort_pointer with the string at
; (sort_pointer + lhs_len + rhs_len +1)
; If they are in the wrong order, set
; swap_flag to 1, else set it to 0.
; The strings' length is each lhs_len
; characters, as we are only looking at
; the left hand sides of table entries.
push_all
mov byte ptr cs:swap_flag,0 ; clear flag
mov bp,1 ; count length of strings
mov si,cs:sort_pointer ; pointer to 1st string
mov di,si ; pointer to second string
add di,lhs_len+ rhs_len + 1
comp1:
mov ah,byte ptr cs:[si] ; get byte from 1st string
mov al,byte ptr cs:[di] ; and a byte from the second
cmp ah,al ; compare them
jb compared ; they're in the right order
je comp2 ; or they are the same
mov byte ptr cs:swap_flag,1 ; else set the flag to say 'swap'
jmp compared ; and our job is done
comp2:
inc si ; bump up pointers
inc di
inc bp ; and change "how many left to compare"
cmp bp,lhs_len + 1 ; whole lhs compared?
jne comp1 ; no, so compare another
compared:
pop_all ; all compared.
ret
sort_compare endp
;
sort_swap proc ; swap the string at sort_pointer with the one at
; (sort_pointer + lhs_len + rhs_len + 1). The string
; has length (lhs_len + rhs_len + 1). This routine
; swaps each byte in turn which, although slower than
; a rep movsb instruction, avoids having to have a
; large buffer to use while the swap takes place.
push_all
mov bp,LHS_LEN + RHS_LEN + 1 ; length of strings
mov si,cs:sort_pointer ; pointer to 1st string
mov di,si ; pointer to second string
add di,bp
swap1:
mov ah,byte ptr cs:[si] ; get byte from 1st string
mov al,byte ptr cs:[di] ; and a byte from the second
mov byte ptr cs:[si],al ; and write them back...
mov byte ptr cs:[di],ah ; in reverse order
inc si ; bump up pointers
inc di
dec bp ; and update counter
cmp bp,0 ; all swapped?
jne swap1 ; no, so swap another
pop_all ; all swapped, so we're done
ret
sort_swap endp
;
to_lower proc
; Force the LHS part of an alias
; in an ALIAS A command to lower case.
push_m <si,ax>
mov si,dx ; pointer into string
add si,10 ; point to start of LHS in ALIAS A
; command string.
lower1:
mov ah,byte ptr ds:[si] ; get char from string
cmp ah,CR ; are we done?
je lower2
cmp ah,SPACE
je lower2 ; stop on space. CR is just for safety
cmp ah,41h
jb dont_lower ; don't convert if character < 'A'
cmp ah,5ah ; or > 'Z'
ja dont_lower
or ah, 00100000b ; else make character lower case
mov byte ptr ds:[si],ah ; and put it back
dont_lower:
inc si ; point to next char in string
jmp short lower1
lower2:
pop_m <ax,si>
ret
to_lower endp
;
list_an_entry proc ; used by ab_list proc. Lists the
; table entry which starts at [di].
; Display LHS string in current
; colour. Terminates on ascii 0.
; However, if the LHS string is of
; the maximum permitted length,
; there won't be a zero and we run
; into the RHS str. So save 1st byte
; of RHS string in cs:list_temp
; and put a zero there instead.
; Replace saved byte when done.
; Do this whatever the length of
; the LHS string, as it's not worth
; checking! The RHS string always ends
; with a 0, so there's no need to
; worry about that one.
push bp
push ax
mov bp,di ; start of LHS string in cs
add bp,LHS_LEN ; point to 1st char of RHS string
mov al,byte ptr cs:[bp] ; get character to save
mov byte ptr cs:list_temp,al; save it
mov byte ptr cs:[bp],0 ; put zero at end of LHS string
mov word ptr cs:list_temp2,bp ; save the address that was altered
pop ax
pop bp
push_all
mov si,di ; start of string
mov bl,cs:colour ; set colour
call disp_str_colour ; display the string
pop_all
push_m <ax,bp>
mov al,byte ptr cs:list_temp; get original byte
mov bp,word ptr cs:list_temp2 ; get its address
mov byte ptr cs:[bp],al ; and put the byte back
pop_m <bp,ax>
; Now put cursor 2 places after LHS so
; the RHS strings line up neatly.
push_all
mov ah,3 ; read crsr position
call get_vpage ; get page into bh
bios_video ; get crsr row into dh, to preserve
mov ah,2 ; set crsr position
call get_vpage ; video page --> bh
mov dl,(LHS_LEN + 2) ; set column. Leave row as is.
bios_video ; do it
pop_all
push_all ; display string until 0 byte.
mov bl,cs:colour ; current colour
add di,LHS_LEN ; skip arg
mov si,di ; address of string
call disp_str_colour ; call proc
pop_all
call crlf ; start a new line
ret
list_an_entry endp
;
ab_write proc ; ALIAS W <pathname> saves table
call are_you_sure ; is user sure?
cmp byte ptr cs:confirm,1 ; did user say yes?
jne write_not_sure ; abandon if not
push_m <ax,bx,cx,dx,bp,si,ds>
push ds
mov bp,dx
mov al, byte ptr ds:[bp+1] ; get length of string
cmp al,7 ; just ALIAS W typed?
jne write1
mov dx,offset cs:default_fn ; use default file if so.
push ax
mov al,byte ptr cs:[def_dir] ; if this string is full of zeroes,
; the default file was not loaded
cmp al,0
pop ax
je not_loaded ; so use the file name we just set up.
mov dx,offset cs:defdir_hdr ; If default file WAS loaded at install
; time, recover its path.
not_loaded:
push cs
pop ds
jmp short write2
write1:
mov ah,0
mov si,ax
add si,2 ; point to CR terminator
add si,bp
mov byte ptr ds:[si],0 ; change CR to 0 to make asciiz
;
add dx,10 ; point to start of filename
write2:
mov cl,0 ; no attributes
mov ah,3ch ; create file
int 21h ; do it. Handle -->ax
;
jnc ab_save_ok ; continue if no error
call disk_error_msg
jmp short ab_save_quit ; else display error msg
ab_save_ok:
mov bx,ax ; write to file. Handle in bx
mov cx,((RHS_LEN + LHS_LEN + 1) * TBL_LEN) + 5 ; table plus signat
mov ax,cs
mov ds,ax
mov dx,offset cs:table_top ; point to data area to be saved
mov ah,40h
int 21h
;
mov ah,3eh ; close file whose handle is in bx
int 21h
ab_save_quit:
pop ds
;
pop_m <ds,si,bp,dx,cx,bx,ax>
write_not_sure:
ret
ab_write endp
;
ab_read proc ; ALIAS R <pathname> loads a table
call are_you_sure ; Ask user to confirm
cmp byte ptr cs:confirm,1 ; is user sure?
jne read_not_sure ; abandon if not
push_m <ax,bx,cx,dx,bp,si,ds>
push ds
;
mov bp,dx
mov al,byte ptr ds:[bp+1] ; get length of string
cmp al,7 ; just ALIAS R typed?
jne read1
mov dx,offset cs:default_fn ; assume default filename if so.
; However, if a pathed version of the
; default file exists, use it instead.
push ax
mov al,byte ptr cs:[def_dir] ; if this string is full of zeroes,
; the default file was not loaded
cmp al,0
pop ax
je not_loaded2 ; so use the file name we just set up.
mov dx,offset cs:defdir_hdr ; If default file WAS loaded at install
; time, recover its path.
not_loaded2:
push cs
pop ds
jmp short read2
read1:
mov ah,0
mov si,ax
add si,2
add si,bp
mov byte ptr ds:[si],0 ; replace CR with 0
;
add dx,10 ; point to start of filename
read2:
mov ah,3dh
mov al,0 ; read mode only
int 21h ; open file for reading
;
jnc ab_load_ok ; continue if no error
call disk_error_msg
jmp short ab_l_quit
ab_load_ok:
mov bx,ax ; put handle in correct place
mov cx,((RHS_LEN + LHS_LEN + 1) * TBL_LEN) + 5 ; table plus signat
mov ax,cs
mov ds,ax
mov dx,offset cs:table_top ; point to destination of loaded bytes
mov ah,3fh ; read file
int 21h
;
mov ah,3eh
int 21h ; close file
ab_l_quit:
pop ds
;
pop_m <ds,si,bp,dx,cx,bx,ax>
call crlf
read_not_sure: ; come here if user says "No"
ret
ab_read endp
;
get_string_from_kbd proc ; The DOSEDIT get-string routine
call update_csize ;make cursor echo insert mode
cli ;turn interrupts off
mov word ptr cs:oldsp,sp ;save the old stack pointer
mov word ptr cs:oldsp+2,ss
mov ss,cs:codeseg ;make a local stack
mov sp,offset stcktop ;set stack pointer to top of stack
sti ;turn interrupts back on
push ax ;save registers
call bufkey ;do buffer keyboard input
pop ax ;restore registers
;
cli ;turn interrupts off
mov ss,word ptr cs:oldsp+2 ;restore the old stack
mov sp,word ptr cs:oldsp
sti ;turn interrupts back on
call small_cursor ; restore cursor size.
ret
;
get_string_from_kbd endp
;function to emulate the dos buffered
;keyboard input routine int 21 ah=0Ah.
;Call to get buffered input from the
;keyboard using the tiny editor.
;Entry:
;ds:dx -> input buffer for the string
;ds:dx+0 = number of chars in buffer
;Exit:
;ds:dx+1 = number of chars entered.
;ds:dx+2 -> string terminated by CR.
bufkey:
push_all
;
mov ax,ds ;es:di -> string storage
mov es,ax
mov di,dx
;
mov cl,[di] ;cl = max number of char to accept
mov ch,0 ;cx = max number of char to accept
dec cx ;sub 1 to make space for the cr
call tinyedt ;get the string
;
mov al,CR ;echo the return
call putc
;
call strlen ;compute the string length
inc di ;es:di -> string length storage
mov es:[di],cl ;save the string length
inc di ;es:di -> storage for the string
;
call cpystr ;copy the string into buffer
mov byte ptr es:[di],cr ;terminate the string with cr
;
pop_all
ret
;call to move output string
;Entry:
;cs:si -> input string terminated by 0
;es:di -> destination for string
;Exit:
;cs:si -> 0 in source string
;es:di -> 0 in destination string
;ax = undefined
cpystr:
mov al,cs:[si] ;get char from source string
mov es:[di],al ;write the destination string
cmp al,0 ;is this the termiation char?
jz cpystr1 ;yes, string moved
inc si ;inc the from pointer
inc di ;inc the two pointer
jmp cpystr ;loop till done
cpystr1:
ret
;
;Little line editor
;Call to get a single line of text from
;the keyboard with editing.
;Entry:
;cx = max chars to accept, excl null.
;Exit:
;cs:si -> string terminated with 0
tinyedt:
push ax ;save registers
push bx
push cx
push dx
push bp
push di
push ds
push es
mov ax,cs ;data segment = code segment
mov ds,ax
mov maxchar,cx ;save the max number of characters
call initlin ;begin editing a new line
call dcinitlin ; Do special init functions for DOS
; compatibility.
tinyed1:
call getc ;get a character
cmp ax,prf_trigger ; is char the prf key?
je tiny22
mov byte ptr cs:prf_multi,0 ; clear flag used to detect multiple
; presses of the prf key.
tiny22:
cmp ax,it_key
je tiny2
mov byte ptr cs:it_multi,0
tiny2:
cmp ax,F6Key ; Translate F6 to Ctrl-Z
jne tiny9
mov ax,01Ah
tiny9:
cmp ax,CR ;is the key a return?
je tinyed2 ;yes, done editing the line
mov bx,offset cmndtbl ;bx -> table of keys and commands
call gotocmd ;lookup the command and execute
call update ;update the display
jmp tinyed1
tinyed2:
call begline ;move the cursor to the beginning
call update ;redraw the display
call endline ;remove the bubble in text
mov si,cursorb ;si -> beginning of the cursor
mov byte ptr [si],0 ;terminate the string
mov si,offset bublbeg ;cs:si -> beginning of the string
call strlen ;compute the string length
cmp cx,shrtstr ;is the string too short to save?
jbe tinyed3 ;yes, don't save it
call cmdput ;no, long enough, record the line
tinyed3:
pop es
pop ds
pop di
pop bp
pop dx
pop cx
pop bx
pop ax
ret
;This routine branches to a command
;based on table lookup.
;Entry:
;ax = command number to lookup in table
;bx -> beginning of lookup table
;Exit:
;ax = command number
;pc = command subroutine address
;Table Format:
;match word,branch word
;last match word must be 0,
;the addr is the no match routine.
gotocmd:
cmp ax,0 ;is it a null command?
jz gotocd3 ;yes, skip it
gotocd1:
cmp [bx],ax ;does table entry match command number?
je gotocd2 ;yes, go do that command
cmp byte ptr [bx],0 ;is this the end of the table?
je gotocd2 ;yes, execute the no match command
add bx,4 ;bx -> next table entry
jmp gotocd1 ;go test next table entry
gotocd2:
add bx,2 ;bx -> branch word
jmp word ptr [bx] ;execute the routine
gotocd3:
ret
;
;call to begin editing a new line
initlin:
call vidstat ;get screen width and display page
mov al,ah ;al = screen width
mov ah,0 ;ax = screen width
mov scrnwdt,ax ;save screen width
mov disppag,bh ;save the display page
;
call getcpos ;get the cursor position
mov cursory,dh ;save cursor position in y
mov al,dl ;al = cursor position in x
mov ah,0 ;ax = cursor position in x
mov cursorx,ax ;save cursor position in x
mov leftx,ax ;save x position of the left most spot
;
mov ax,scrnwdt ;ax = width of the screen
sub ax,leftx ;ax = length of editor line
mov linelen,ax ;save editor line length
;
call delline ;delete everything in the buffer
;
mov si,offset scrnimg ;fill image buffer with zeros
mov cx,maxswdt ;cx = buffer size
initln1:
mov byte ptr [si],0 ;put in a zero
inc si ;si -> next spot in the buffer
loop initln1 ;loop till done
ret
;
dcinitlin: ; Initialize for DOS compatibility.
; As we enter the line editor, cmdpnt
; points to where, in the history
; buffer, the command about to be
; entered will start. Get the text of
; the PREVIOUS command and store it in
; dcbuffer. This is the command that
; will be recalled if user presses the
; invisible DOS-like editing keys.
push_m <bx,si,di,ax>
call cmdprev ; get start of previous command into si
; Now copy the command into dcbuffer.
mov di,offset cs:dcbuffer ; destination
mov word ptr cs:dcpointer,di ; initialise dcpointer
push si
call cmdnext
pop si
dcinit2:
mov ah,byte ptr cs:[si] ; get byte from command buffer
mov byte ptr cs:[di],ah ; put in destination
cmp ah,0 ; are we done?
je dcinit1
call cmdinc ; get next byte from buffer
inc di
jmp short dcinit2
dcinit1:
pop_m <ax,di,si,bx>
ret
;call to initialize the tiny editor
inittny:
call vidstat ;get the display page
mov disppag,bh ;save the display page
mov cursorb,offset bublbeg ;set pointer to cursor beginning
mov cursore,offset bublend ;set pointer to cursor end
call noundel ;mark nothing to undelete
call cmdinit ;initialize the old command recorder
ret
;Editor commands
F3proc: ; Call to implement the F3 key, and
; make it work like it does with DOS.
mov si,cs:dcpointer
push ax
push bx
mov ax,word ptr cs:cursorb
mov bx,offset cs:bublbeg
sub ax,bx ; AX = number of chars left of cursor
push ax
call delline ; delete whats in the buffer now. Can't
; do this before calculating ax, cos
; it destroys cursorb.
pop ax
add word ptr cs:cursorb,ax ; Move destination for the incoming
; characters past the ones already
; typed.
pop bx
pop ax
;
;Now carry on like a normal cursup.
f3proc1:
call cmdotrg ;get a character from the last command
cmp al,0 ;is it the termination char?
jz f3proc2 ;yes
cmp al,0FFh
je f3proc1
call putin ;no, place the char in the bubble
jmp f3proc1
;
f3proc2:
call noundel ;mark nothing undeletable
call setcol ;update start display column number
call cmdnext
ret
;Call to move the cursor up one line,
;show previous command in buffer.
cursup:
call delline ;delete what's in the buffer now
call cmdprev ;si -> previous command
cursup1:
call cmdotrg ;get a character from the last command
cmp al,0 ;is it the termination char?
jz cursup2 ;yes
call putin ;no, place the char in the bubble
jmp cursup1
cursup2:
call noundel ;mark nothing undeletable
call setcol ;update start display column number
ret
;call to move the cursor down one line,
;show next command in buffer.
cursdn:
call delline ;delete whats in the buffer now
call cmdnext ;si -> next command
cursdn1:
call cmdotrg ;get a character from the next command
cmp al,0 ;is it the termination char?
jz cursdn2 ;yes
call putin ;no, place the char in the bubble
jmp cursdn1
cursdn2:
call noundel ;mark nothing undeletable
call setcol ;update start display column number
ret
;Call to move the cursor to beginning
;of the line.
begline:
cmp cursorb,offset bublbeg ;is the cursor at the beginning?
je beglin1 ;yes, all done
call curslf ;move the cursor over 1
jmp begline
beglin1:
ret
;Call to move the cursor to the end of
;the line.
endline:
cmp cursore,offset bublend ;is the cursor at the end?
je endlin1 ;yes, all done
call cursrt ;move the cursor over 1
jmp endline
endlin1:
ret
;call to move the cursor left one word
wordl:
call curslf ;move cursor 1 to the left
mov si,cursorb ;si -> character on the left of cursor
cmp si,offset bublbeg ;is it at the beginning of the bubble?
je wordl1 ;yes, all done moving
mov al,[si-1] ;al = character on the left
call wordchr ;is it a legal word character?
jnc wordl ;yes, go eat the char
call curslf ;move one more across the white char
wordl1:
ret
;Call to move the cursor left one word
wordr:
call cursrt ;move one character to the right
mov si,cursore ;si -> character on the right of cursor
cmp si,offset bublend ;is it at the end of the bubble?
je wordr1 ;yes, all done moving
mov al,[si+1] ;al = character on the right
call wordchr ;is it a legal word character?
jnc wordr ;yes, go eat the char
call cursrt ;move one more across the white char
wordr1:
ret
;Call to move the cursor left one char
curslf:
cmp cursorb,offset bublbeg ;is the cursor at the beginning?
je curslf1 ;yes, don't move it
dec cursorb ;cursorb -> character left of cursor
mov si,cursorb ;si -> cursor beginning
mov di,cursore ;di -> cursor end
mov al,[si] ;al = character left of the cursor
mov [di],al ;move character right of the cursor
dec cursore ;cursore -> end of the new cursor
call noundel ;mark nothing undeletable
call setcol ;update start display column number
curslf1:
ret
;Call to move the cursor right one char
cursrt:
cmp cursore,offset bublend ;is the cursor at the end?
je cursrt1 ;yes, don't move it
inc cursore ;cursore -> character right of cursor
mov si,cursorb ;si -> cursor beginning
mov di,cursore ;di -> cursor end
mov al,[di] ;al = character right of the cursor
mov [si],al ;move character left of the cursor
inc cursorb ;cursorb -> new beginning of the cursor
call noundel ;mark nothing undeletable
call setcol ;update start display column number
cursrt1:
ret
;call to delete the line the cursor's on
delline:
call dellinl ;delete everything to the left
call dellinr ;delete everything to the right
ret
escproc:
call delline ; When user hits ESC, delete the
; current line, and reset dcpointer
push si
mov si,offset cs:dcbuffer
mov word ptr cs:dcpointer,si
pop si
ret
;
;call to delete all char to beginning
;of line.
dellinl:
cmp cursorb,offset bublbeg ;is the cursor at the beginning?
je dellnl1 ;yes, all deleted
call delchrl ;no, delete char on the left
jmp dellinl ;loop till all gone
dellnl1:
ret
;call to delete to end of line
dellinr:
cmp cursore,offset bublend ;is the cursor at the end?
je dellnr1 ;yes, all deleted
call delchrr ;no, delete char on the right
jmp dellinr ;loop till all gone
dellnr1:
ret
;call to delete word left of the cursor
delwrdl:
call delchrl ;delete the character to the left
mov si,cursorb ;si -> character on the left of cursor
cmp si,offset bublbeg ;is it at the beginning of the bubble?
je delwrl1 ;yes, all done deleting
mov al,[si-1] ;al = character on the left
call wordchr ;is it a legal word character?
jnc delwrdl ;yes, go eat the char
delwrl1:
ret
;call to delete a word right
;of the cursor.
delwrdr:
call delchrr ;delete the character to the right
mov si,cursore ;si -> character on the right of cursor
cmp si,offset bublend ;is it at the end of the bubble?
je delwrr1 ;yes, all done deleting
mov al,[si+1] ;al = character on the right
call wordchr ;is it a legal word character?
jnc delwrdr ;yes, go eat the char
delwrr1:
ret
;call to delete char left of cursor
delchrl:
cmp cursorb,offset bublbeg ;is the cursor at the beginning?
je delchl1 ;yes, don't delete
dec cursorb ;delete the character
inc unleft ;make the character undeletable
call setcol ;update start display column number
delchl1:
ret
delchrr:
; Call to delete char right of cursor
; However, if user hasn't typed any
; chars yet, delete a character from the
; dcbuffer.
push bx
call bublcnt ; bx <-- no of chars typed
cmp bx,0
pop bx
jne del_right
; No chars have been typed, so
; effectively delete a char from the
; dcbuffer by incrementing dcpointer.
inc word ptr cs:dcpointer
ret
del_right:
cmp cursore,offset bublend ;is the cursor at the end?
je del_dcbuff ;yes, so delete from dcbuffer instead
inc cursore ;delete the character
inc unright ;make the character undeletable
call setcol ;update start display column number
delchr1:
ret
del_dcbuff:
inc byte ptr cs:dcpointer
ret
;call to undelete text from the buffer
undelet:
mov ax,unleft ;al = # of char to undelete on left
add cursorb,ax ;undelete on the left
mov ax,unright ;al = # of char to undelete on right
sub cursore,ax ;undelete on the right
call noundel ;mark nothing undeletable
call setcol ;update start display column number
ret
;call to place a character in the edit
;buffer, filter out trash first
nomatch:
call filter ;filter out trash
jc nomtch1 ;branch on trash
call putin ;else insert character in edit buffer
call noundel ;mark nothing undeletable
call setcol ;update start display column number
nomtch1:
ret
;Editor Display Functions
;call to update the display line
update:
push ax ;save registers
push bx
push dx
push si
push di
mov si,offset bublbeg ;si -> first char in bubble
mov bx,startx ;bx = start column # of display line
call findcol ;si -> first character to display
mov di,offset scrnimg ;di -> screen image buffer
mov updatex,0 ;x pos on display line to update
update1:
cmp si,cursorb ;does si -> the cursor in the bubble?
jne update2 ;no
mov ax,updatex ;yes, save the editor cursor position
add ax,leftx ;add the starting left column number
mov edcursx,ax
mov si,cursore ;si -> end of cursor marker
inc si ;si -> first char right of the cursor
update2:
cmp si,offset bublend+1 ;does si -> end of the buffer
je update5 ;yes, go blank end of line
mov al,[si] ;al = next char to display
inc si ;si -> next char in the bubble
cmp al,tab ;is the character a tab?
jne update4 ;no, go display the character
update3:
mov al,' ' ;yes, expand the tab, display a blank
call updatec ;display the blank
jz update6 ;branch if update complete
mov ax,updatex ;ax = current update column
add ax,startx ;ax = x pos from start of edit line
and ax,111b ;ax = column mod 8
jnz update3 ;loop till tab expanded
jmp update1 ;go display the next character
update4:
call updatec ;display a normal character
jz update6 ;branch if update complete
jmp update1 ;go display the next character
update5:
mov ax,linelen ;blank end of line
dec ax ;ax = right most column number
cmp ax,updatex ;has the full screen been displayed?
jz update6 ;yes, all done
cmp byte ptr [di],0 ;has this character never been changed?
jz update6 ;yes, don't change it
mov al,' ' ;end of line, display blanks
call updatec ;display the character
jnz update1 ;go display next char if not done
update6:
mov dx,edcursx ;position the hardware editor cursor
call setcurx
mov cursorx,dx ;save the cursor x value
pop di ;restore registers and return
pop si
pop dx
pop bx
pop ax
ret
;call to update a single char on display
;Entry:
;al = character to write
;di -> char in same pos on screen
;cursorx = pos of hardware cursor in x
;updatex = next x loc to update on scrn
;Exit:
;cursorx = loc of the hw cursor in x
;updatex = new x loc to update on scr
; next time
;di -> next character in screen image
;z flag set if line fully displayed
updatec:
cmp al,[di] ;is the char already shown?
je updatc2 ;yes, don't change it
mov dx,updatex ;no, must display the character
add dx,leftx ;dl = desired x location to update
cmp cursorx,dx ;is the cursor in the correct spot?
je updatc1 ;yes, don't need to move it
call setcurx ;no, set the cursor column
mov cursorx,dx ;save the cursor x value
updatc1:
call putc ;display the character
inc cursorx ;increment the hardware cursor column
mov [di],al ;put the character in the image buffer
updatc2:
inc updatex ;increment the next update column no.
inc di ;di -> next char in image buffer
mov ax,linelen ;ax = line length
dec ax ;ax = left most column, line relative
cmp ax,updatex ;set z flag if display line is full
ret
;Primitive Editor Functions
;call to filter out unwanted characters
;Entry:
;ax = keyboard character
;Exit:
;ax = keyboard character
;carry set if key filter out
;all other registers unchanged
filter:
cmp al,LF ;is it a line feed?
je filter2 ;yes, filter it out
filter1:
clc ;don't filter
ret ;return with no carry
filter2:
stc ;do filter the character
ret ;return with no carry
;insert a char into bubble buffer,
;no filtering
;Entry:
;al = character
;Exit:
;all registers unchanged
putin:
push ax ;save registers
push si
call bublcnt ;bx = number of characters in bubble
cmp bx,maxchar ;are more characters allowed?
jae putin1 ;no, trash the character
mov si,cursorb ;si -> beginning of the cursor
mov [si],al ;put the character in the bubble
inc si ;si -> next spot in the bubble
cmp si,cursore ;is the bubble full?
je putin1 ;yes, don't update the cursor position
mov cursorb,si ;update the beginning of the cursor
putin1:
pop si ;restore registers
pop ax
; If insert mode is off, make a call
; to dellchrr, to delete the character
; to the right of the cursor. This
; is how we achieve overwrite mode.
cmp byte ptr cs:ins_mode,1 ; insert mode on?
je putin2 ; yes, so we're ok
call delchrr ; overwrite mode required
putin2:
ret
;call to compute the number of
;characters in the bubble buffer
;Exit:
;bx = number of characters in the buffer
;all other registers unchanged
bublcnt:
mov bx,offset bublend ;add char count before & after bubble
sub bx,cursore
add bx,cursorb
sub bx,offset bublbeg
ret
;call to mark nothing undeletable
noundel:
mov unleft,0
mov unright,0
ret
;find address of char at column n
;Enter:
;si -> beginning of string
;bx = desired column number
;Exit:
;si -> character at column n
;all other registers unchanged
findcol:
push ax ;save registers
push bx
push cx
mov cx,0 ;cx = column counter
cmp cx,bx ;is this the correct column number?
je findcl3 ;yes, all done
inc bx ;incrememt the desired column number
findcl1:
mov al,[si] ;al = character from string
cmp al,tab ;is it a tab?
jne findcl2 ;no, normal character
add cx,8 ;yes, expand tab, add tab width
and cx,0fff8h ;cx = column at next tab stop
cmp cx,bx ;is this the correct column?
jae findcl3 ;yes, stop looking
inc si ;no, si -> next char in string
jmp findcl1 ;branch if this not desired column
findcl2:
inc cx ;no, add 1 column for displayable char
cmp cx,bx ;is this the correct column?
je findcl3 ;yes, stop looking
inc si ;si -> next char in string
jmp findcl1 ;keep looking
findcl3:
pop cx ;restore registers and return
pop bx
pop ax
ret
;call to compute the column
;number to begin displaying
;Entry:
;startx = current start col
;of display line
;Exit:
;startx = new starting column
;of the display line
;all registers unchanged
setcol:
push ax ;save registers
push bx
call colcurs ;compute cursor column number
cmp bx,startx ;is the cursor left of the screen?
jae setcol1 ;no
mov startx,bx ;yes, set the start spot same as crsr
jmp setcol2 ;all done
setcol1:
mov ax,linelen ;ax = width of the display line
dec ax ;ax = right most display column
add ax,startx ;ax = x pos of last displayed char
cmp bx,ax
jb setcol2 ;branch if cursor is on the screen
sub bx,linelen ;cursor right of display line
add bx,2 ;compute new starting column
mov startx,bx
setcol2:
pop bx ;restore registers and return
pop ax
ret
;call to compute the column number the
;cursor is on, from beginning of line
;Exit:
;bx = cursor column number
;all other registers unchanged
colcurs:
push ax ;save registers
push si
mov si,offset bublbeg ;si -> first char on line
mov bx,0 ;zero column counter
colcur1:
cmp si,cursorb ;does si -> the cursor?
je colcur3 ;yes, found the cursor column
mov al,[si] ;get char from line
inc si ;si -> next char on line
cmp al,tab ;is it a tab?
jne colcur2 ;no, normal character
add bx,8 ;add distance between tab stops
and bx,0fff8h ;bx = column of next tab stop
jmp colcur1 ;go check next character
colcur2:
inc bx ;add 1 column for displayable char
jmp colcur1 ;go check next char
colcur3:
pop si ;restore registers and return
pop ax
ret
;Functions to record and retrieve
;past lines edited
;call to find the previous command
;Exit:
;si -> beginning of the previous cmd
;all other registers unchanged
cmdprev:
mov si,cmdpnt ;si -> current command
cmp si,cmdold ;is this the oldest command?
je cmdprv1 ;yes, return pointer to this one
call cmdbefr ;si -> the previous command
mov cmdpnt,si ;si -> new current command
cmdprv1:
ret
;call to find the next command
;Exit:
;si -> beginning of the next command
;all other registers unchanged
cmdnext:
mov si,cmdpnt ;si -> current command
cmp si,cmdnew ;is this the newest command?
je cmdnxt1 ;yes, return pointer to this one
call cmdaftr ;si -> the next command
mov cmdpnt,si ;si -> new current command
cmdnxt1:
ret
;call to enter cmd into the ring
;Entry:
;si -> command terminated by zero
;to insert into the ring
cmdput:
push ax ;save registers
push si
cmp byte ptr [si],0 ;is it a null command?
jz cmdput2 ;yes, don't put it in
cmdput1:
mov al,[si] ;get a character to insert
inc si ;si -> next char to insert
call cmdinrg ;put it in the ring
cmp al,0 ;is it the termination zero?
jnz cmdput1 ;no, go insert the next one
cmdput2:
mov si,cmdnew ;si -> spot for the next new command
mov cmdpnt,si ;put the command pointer here
mov byte ptr [si],0 ;make new command a null string
pop si ;restore registers and return
pop ax
ret
;call to get a char from the ring
;Entry:
;si -> character in the ring
;Exit:
;al = character from the ring
;si -> next character in the ring
cmdotrg:
mov al,[si] ;get char from the ring
call cmdinc ;si -> next char in the ring
ret
;call to enter a char into the ring
;Entry:
;al = character to insert
;cmdnew -> storage for new cmd char
;Exit:
;all registers unchanged
cmdinrg:
push si ;save registers
mov si,cmdnew ;si -> storage for new commands
mov [si],al ;save the new command character
call cmdinc ;increment the pointer
mov cmdnew,si ;update pointer for new commands
cmp si,cmdold ;is an old command in the way?
jne cmdinr1 ;no
mov si,cmdold ;yes, remove the oldest command
call cmdaftr ;si -> next to oldest command
mov cmdold,si ;save pointer to new oldest command
cmdinr1:
pop si
ret
;call to search for previous command
;Entry:
;si -> beginning of current command
;Exit:
;si -> beginning of previous command
;all other registers unchanged
cmdbefr:
call cmddec ;si -> termination of previous command
cmdbfr1:
call cmddec ;si -> previous character
cmp byte ptr [si],0 ;does si -> termination char?
jnz cmdbfr1 ;no, keep looping
call cmdinc ;si -> first char of command
ret
;call to search for the next command
;Entry:
;si -> beginning of current command
;Exit:
;si -> beginning of next command
;all other registers unchanged
cmdaftr:
call cmdinc ;si -> next character
cmp byte ptr [si],0 ;does si -> termination char?
jnz cmdaftr ;no, keep looping
call cmdinc ;si -> first char of command
ret
;call to increment a pointer into
;the commands buffer.
;Exit:
;si = increment pointer
;all other registers unchanged
cmdinc:
inc si ;inc the pointer
cmp si,offset cmdbot ;is the pointer outside the ring?
jbe cmdinc1 ;no
mov si,offset cmdtop ;yes, set pointer to the top
cmdinc1:
ret
;call to decrement a pointer into the
;commands buffer.
;Exit:
;si = decremented pointer
;all other registers unchanged
cmddec:
dec si ;dec the pointer
cmp si,offset cmdtop ;is the pointer outside the ring?
jae cmddec1 ;no
mov si,offset cmdbot ;yes, set pointer to the bottom
cmddec1:
ret
;call to initialize the command
;recording functions.
cmdinit:
mov si,offset cmdtop ;si -> beginning of command ring
mov cmdold,si ;initialize all pointer to top of ring
mov cmdnew,si
mov cmdpnt,si
mov si,offset cmdtop ;fill command buffer with null strings
mov cx,cmdlen ;cx = buffer size
cmdint1:
mov byte ptr [si],0 ;put in a zero
inc si ;si -> next spot in the buffer
loop cmdint1 ;loop till done
ret
;DOS and ROM Interface Functions
;call to get the state of the video
;Exit:
;al = display mode
;ah = number of char columns on screen
;bh = current active display page
;bl = undefined
;all other registers unchanged
vidstat:
push si ;save registers
push di
mov ah,15 ;get the video state
bios_video
pop di ;restore registers and return
pop si
ret
;call to get the cursor position
;Exit:
;dl = cursor position in x
;dh = cursor position in y
;all other registers unchanged
getcpos:
push ax ;save registers
push bx
push si
push di
mov bh,disppag ;bh = display page
mov ah,3 ;read the cursor position
bios_video
pop di ;restore registers and return
pop si
pop bx
pop ax
ret
;call to set the cursor x position
;Entry:
;dl = cursor position in x
;Exit:
;all registers unchanged
setcurx:
push ax ;save registers
push bx
push si
push di
mov dh,cursory ;dh = cursor line number
mov bh,disppag ;bh = display page
mov ah,2 ;set the cursor position
bios_video
pop di ;restore registers and return
pop si
pop bx
pop ax
ret
;call to display a string
;Entry:
;si -> string terminated by zero
;Exit:
;all registers unchanged
puts:
push ax ;save registers
push si
puts1:
mov al,[si] ;get char from the string
inc si ;si -> next char in string
cmp al,0 ;is it the termination zero?
jz puts2 ;yes, all done
call putc ;display the character
jmp puts1 ;go display the next character
puts2:
pop si ;restore registers and return
pop ax
ret
putc: ;display char in al
disp_ch al
ret
;call to get a char from the console
;keyboard without echo
;Exit:
;ax = char from keyboard
;ah = 1 if extended keycode else 0
;all other registers unchanged
getc:
mov ah,8 ;read keyboard without echo
int 21h
cmp al,0 ;is it an extended key?
jz getc1 ;yes, go get the keycode
mov ah,0 ;no, ax = keyboard code
ret
getc1:
mov ah,8 ;read keyboard without echo
int 21h
mov ah,1 ;ax = extended keycode
ret
;Misc Functions
;call to compute the length of a string
;Entry:
;cs:si -> string terminated by zero
;Exit:
;cx = string length
;all other registers unchanges
strlen:
push si ;save registers
mov cx,0 ;zero the counter
strlen1:
cmp byte ptr cs:[si],0 ;is this the termination character?
jz strlen2 ;yes, all done
inc si ;si -> next char in string
inc cx ;inc the char counter
jmp strlen1 ;loop till done
strlen2:
pop si ;restore registers and return
ret
;call to check for legal word character
;Entry:
;al = char to test
;Exit:
;cf set if invalid char
;all other registers unchanged
wordchr:
push bx ;save bx
mov bx,'az' ;is the char a lower case letter?
call chrrang
jnc wordch1 ;yes, return with no carry
mov bx,'AZ' ;is the char an upper case letter?
call chrrang
jnc wordch1 ;yes, return with no carry
mov bx,'09' ;is the char a number?
call chrrang ;return with status in carry
wordch1:
pop bx ;restore bx and return
ret
;call to test if a character is
;between or included by two characters
;Entry:
;al = char to check
;bl = upper match char
;bh = low match char
;Exit:
;cf clear if valid match
;bl = undefined
;all other registers unchanged
chrrang:
cmp al,bh ;is the char < bh
jc chrrng1 ;yes, no match, return with carry
inc bl ;is the char > bl
cmp al,bl ;compare with upper limit
cmc ;invert the carry flag
chrrng1:
ret
;
inskey proc ; Toggle insert mode, cos user has
; pressed insert key.
; However, if bublcnt = 0, obey the
; rules of DOS compatibility and insert
; an 0FFh byte into dcbuffer.
push bx
call bublcnt
cmp bx,0 ; Has user typed anything yet?
pop bx
jne ins_normal ; If yes, continue normally
; Insert a 0FFh byte into dcbuffer,
; starting at cs:[dcpointer].
push si
mov si,offset cs:dcbufend ; start at end of dcbuffer
sub si,2 ; point to last byte of dcbuffer
; before end marker
cmp byte ptr cs:[si],0 ; is there room for a char to be
; inserted?
je ins_is_room ; continue if there's room, ie last
; char is zero
cmp byte ptr cs:[si],0FFh
je ins_is_room ; also continue if last char is 0FFh
pop si ; else, tidy up the stack...
ret ; ...and return.
ins_is_room:
push bx
push ax
mov bx,word ptr cs:dcpointer
shift_cont:
mov ah,byte ptr cs:[si] ; get character from dcbuffer
mov byte ptr cs:[si+1],ah ; shift it right by one char
cmp si,bx ; are we done shifting?
je dun_shifting
dec si
jmp short shift_cont
dun_shifting:
mov byte ptr cs:[si],0FFh ; put blank in newly-created space
pop ax
pop bx
pop si
ret ; End of dcbuffer insert routine
ins_normal:
cmp byte ptr cs:ins_mode,0 ; is mode currently overwrite?
jne ins01 ; no, so change to overwrite
mov byte ptr cs:ins_mode,1 ; change to insert mode
jmp short ins02
ins01:
mov byte ptr cs:ins_mode,0 ; set mode to overwrite
ins02:
call update_csize ; update cursor size to reflect mode
ret
inskey endp
;
update_csize proc
cmp byte ptr cs:ins_mode,0 ; is mode set to overwrite?
jne ins_csize ; no, so set csize to insert size
call small_cursor ; yes, so make small cursor
jmp short ins2
ins_csize:
call big_cursor
ins2:
ret
update_csize endp
;
big_cursor proc ; Add 2 scan lines to crsr height
cmp byte ptr cs:[csize],2 ; is cursor already big?
je is_big ; yes, so do nothing
push_m <ax,bx,cx,dx,di,si>
mov ah,3
call get_vpage
bios_video ; returns height of cursor in cl
dec ch
dec ch ; increase the height of the cursor
; by 2 scan lines.
mov ah,1
call get_vpage
bios_video ; and set new cursor height
mov byte ptr cs:[csize],2 ; set status to say crsr is big
pop_m <si,di,dx,cx,bx,ax>
is_big:
ret
big_cursor endp
;
small_cursor proc ; Shrink crsr height by 2 scan lines
cmp byte ptr cs:[csize],1 ; is cursor already small?
je is_small ; yes, then do nothing
push_m <si,di,ax,bx,cx,dx>
mov ah,3
call get_vpage
bios_video ; returns start line in ch
inc ch
inc ch ; shrink the height of the cursor
; by 2 scan lines.
mov ah,1
call get_vpage
bios_video ; and set new cursor height
mov byte ptr cs:[csize],1 ; set status to say crsr is small
pop_m <dx,cx,bx,ax,di,si>
is_small:
ret
small_cursor endp
;
do_prf proc ; User pressed prf trigger key for the
; first time, while entering a command.
; Search the
; stored commands for matches with
; however many characters the user
; has typed so far.
; If a match is found, update display.
; The order of search is to start at
; cmdpnt, which is where the next cmd
; to be entered would be stored. We
; then work backwards,towards cmdtop,
; getting the most recent commands. We
; wrap from cmdtop to cmdbot once, and
; searching stops when cmdpnt is
; reached for the second time.
push bx
call bublcnt ; bx <-- no of chars typed by user
cmp bx,0 ; has user typed anything yet?
pop bx
je no_prf ; no, so do nothing
cmp byte ptr cs:prf_multi,0 ; is this another press of the prf key
; straight after the last one?
je no_multi ; no, so carry on
push_all ; prepare for a multiple prf
mov si,word ptr cs:prf_pos ; restore si from last prf proc
mov bp,0 ; go round the whole stack again
; Actually, there's no reason to go
; all the way round again. We SHOULD
; save bp the first time round, and
; restore it for multiple prf presses.
jmp short prf2
no_multi:
push_all
mov si,word ptr cs:cmdpnt ; posn where next cmd will be stored
mov bp,0
prf2:
call cmdbefr ; SI now points to the first char of
; the latest command.
cmp bp,0 ; After calling cmdbefr for
; the FIRST TIME, save SI in BP.
jne prf1
mov bp,si
jmp short prf3
prf1:
cmp bp,si ; On all but first time round, check
jne prf3 ; if bp=si. If so, we've come full
; circle and have checked all commands.
jmp prf_done
prf3:
mov di,offset cs:bublbeg ; point to first word of user's command
call prf_compare ; compare word at [si] with one at [di]
cmp byte ptr cs:prf_cflag,1 ; was a match found?
je prf_match ; yes, so update display
jmp short prf2 ; No match. Get next cmd from stack
; and try again.
prf_match:
mov word ptr cs:prf_pos,si ; Match found. Save address of start of
; matching command...
call prf_disp ; ...and put it on screen
prf_done:
mov byte ptr cs:prf_multi,1 ; set flag. When any key apart from
; the prf trigger is pressed, this flag
; gets cleared, so if it is still set
; on entry to do_prf next time, then
; we have a multiple prf request and
; look for the next match, rather than
; starting from cmdpnt again.
pop_all
no_prf:
ret
do_prf endp
;
prf_compare proc
; This proc compares the characters
; in the user's partly-typed command
; with the same number of characters
; in the command at [si], which is one
; in the dosedit buffer. Sets prf_cflag
; if match found.
; The chars at [si] is in the dosedit
; command buffer, and may wrap around.
; Therefore, we can't use a repe cmpsb
; for the comparison. Instead, we keep
; calling cmdinc, which increments si
; and will wrap from bottom to top of
; the command stack if necessary.
mov byte ptr cs:prf_cflag,0 ; clear flag
push_m <ax,si,di,bx>
call bublcnt ; bx <-- no of chars typed by user.
; Used by this proc to count how many
; comparisons we need to make.
cmp byte ptr cs:prf_multi,1 ; Is this a multiple prf press?
jne prf_c2 ; No, so carry on
mov bx,word ptr cs:prf_bx ; It is a multiple press, so use the
jmp prf_c4 ; value of bublcnt from last time.
; This way, we only look for matches
; in the part of the string that the
; user actually typed, and not in the
; part that prf added last time.
prf_c2:
mov word ptr cs:prf_bx,bx ; First time round, save bublcnt value.
prf_c4:
mov ah,byte ptr cs:[di] ; get a byte from user's string
mov al,byte ptr cs:[si] ; and one from command stack
or ax,0010000000100000b ; force chars to lower case
cmp bx,0 ; have we compared enough characters?
je prf_c1 ; yes, then match was found
cmp ah,al ; are they equal?
jne prf_c3 ; no match. Exit and leave flag clear.
inc di ; chars are equal, so go get next ones
call cmdinc ; inc si, but watch for wrap
dec bx ; count no of comparisons made
jmp short prf_c4 ; and off we go again
prf_c1:
mov byte ptr cs:prf_cflag,1 ; indicate that match was found
prf_c3:
pop_m <bx,di,si,ax>
ret
prf_compare endp
;
prf_disp proc ; If do_prf finds a match, then this
; proc is called. It is almost
; identical to cursup, which is called
; by the dosedit routine when the user
; presses up-arrow to retrieve the
; previous command. However, address
; of the cmd to be retrieved is taken
; from prf_pos rather than from a call
; to cmdprev.
push_all
call delline ;delete what's in the buffer now
mov si,word ptr cs:prf_pos ; get address of matching command that
; do_prf found.
prf_disp1:
call cmdotrg ;get a character from the last command
cmp al,0 ;is it the termination char?
jz prf_disp2 ;yes
call putin ;no, place the char in the bubble
jmp prf_disp1
prf_disp2:
call noundel ;mark nothing undeletable
call setcol ;update start display column number
pop_all
ret ; Pointers all set. The actual update
; to the display will happen when the
; update proc is called.
prf_disp endp
;
it_proc proc ; Called when user presses the 'it'
; key, which is currently F8.
; Retrieves all but the first word of
; the previous command, and sticks it
; on the end of the part-typed command.
; Unlike prf, this proc doesn't check
; that the first words match.
call cmdprev ;SI -> previous command
push si
it2:
cmp byte ptr cs:[si],SPACE
je it1
inc si
jmp short it2
it1:
inc si ; SI now points to the first char
; after the space in the previous
; command. This is where characters
; will be retrieved from.
push ax
push bx
mov ax,word ptr cs:cursorb
mov bx,offset cs:bublbeg
sub ax,bx ; AX = number of chars left of cursor
push ax
call delline ; delete whats in the buffer now. Can't
; do this before calculating ax, cos
; it destroys cursorb.
pop ax
cmp byte ptr cs:it_multi,1 ; if multiple F8 in operation,
jne it6 ; then use old cursorb
push bx
mov bx,word ptr cs:it_save
mov word ptr cs:cursorb,bx
pop bx
jmp short it5
it6:
add word ptr cs:cursorb,ax ; Move destination for the incoming
; characters past the ones already
; typed.
mov bx,word ptr cs:cursorb
mov word ptr cs:it_save,bx ; save cursorb, to use if multiple
; presses of F8 detected.
it5:
pop bx
pop ax
;
push si
mov si,word ptr cs:cursorb
cmp byte ptr cs:[si-1],SPACE ; Did user leave a space
; before pressing the IT key?
pop si
je it3 ; Yes, then we're ok
push si
mov si,word ptr cs:cursorb
mov byte ptr cs:[si],SPACE ; Else force a space into string
inc si
mov word ptr cs:cursorb,si
pop si
;Now carry on like a normal cursup.
it3:
call cmdotrg ;get a character from the last command
cmp al,0 ;is it the termination char?
jz it4 ;yes
call putin ;no, place the char in the bubble
jmp it3
it4:
call noundel ;mark nothing undeletable
call setcol ;update start display column number
pop si
mov byte ptr cs:it_multi,1 ; set flag, which is cleared after
; getc is called. If it's still set
; on entry to it_proc, then multiple
; presses of F8 are occurring.
ret
it_proc endp
;
f1proc proc ; Do nothing if F1 pressed
ret
f1proc endp
;
pg_up_proc proc ;PgUp moves pointers to start of
;command buffer.
push si
push bp
pgup_top:
call cmdprev ; get previous command into si
mov bp,si ; and save it in bp
call cmdprev ; get previous command again
cmp si,bp ; has value changed?
je pgup_done ; no, so we're at the top
jmp short pgup_top ; not there yet
pgup_done:
pop bp
pop si
ret
ret
pg_up_proc endp
;
pg_dn_proc proc ;PgDn moves pointers to end of
;command buffer.
push si
push bp
pgdn_top:
call cmdnext ; get next command into si
mov bp,si ; and save it in bp
call cmdnext ; get next command again
cmp si,bp ; has value changed?
je pgdn_done ; no, so we're at the end
jmp short pgdn_top ; not there yet
pgdn_done:
pop bp
pop si
ret
pg_dn_proc endp
;
also_proc proc ; The F10 key is the 'also' key.
; Brings back the first word of the
; previous command, up to & including
; the first space character.
call delline ;delete what's in the buffer now
call cmdprev ;si -> previous command
mov al,0 ; don't let al be 20h on entry
also1:
cmp al,SPACE ; Was last char a space?
jz also2 ; yes, then we have enough characters
call cmdotrg ;get a character from the last command
cmp al,0 ;is it the termination char?
jz also2 ;yes
call putin ;no, place the char in the bubble
jmp also1
also2:
call noundel ;mark nothing undeletable
call setcol ;update start display column number
ret
also_proc endp
;
; Now, a procedure to display a
; string, using a screen
; attribute that can be specified
; by the caller. On entry, SI
; must point to the offset of the
; string, which must be in the
; CODE SEGMENT. BL should be set
; to the attribute required.
; Strings of longer than 80
; chars should have a crlf at
; the end of each line.
;
; Strings should end in a cr,lf so
; that the end of this routine can
; display a space in white after
; displaying the string. If this
; is not done, the default colour
; is not always re-set properly.
;
; Always terminates on ascii 0.
; Won't terminate on $.
disp_str_colour proc
call get_vpage ; get vpage into bh
mov cx,1 ; write each char once
mov ax,cs ; the string must be in cs, but...
cmp byte ptr cs:echo_flag,1 ; if flag is set, string is in ds
jne all_ok
mov ax,ds
all_ok:
mov ds,ax
cld
again:
lodsb ; get char into al
cmp al,0
je done
cmp al,CR
jne try1
disp_ch CR
jmp short again
try1:
cmp al,LF
jne try2
disp_ch LF
jmp short again
try2:
mov ah,09h
bios_video ; disp char
push_all
mov ah,3
bios_video ; get crsr pos
inc dl
;
mov ah,2 ; set new crsr pos
bios_video
pop_all
;
jmp again
done:
; display a space in white, to reset
; default colour. Should really check
; what default colour was, and save it.
mov al,SPACE
mov bl,WHITE
mov ah,9
mov cx,1
bios_video
ret
disp_str_colour endp
;
if debug ; Assemble only if DEBUG equate is true.
hw_blip proc ; Make a bleep. This proc is hardware
; coded to aviod DOS and BIOS calls.
push ax
push bx
push cx
push dx
push di
mov di,2500 ; frequency in Hz
mov bx,15 ; duration in 1/100 secs
mov al,0b6h
out 43h,al
mov dx,14h
mov ax,4f38h
div di
out 42h,al
mov al,ah
out 42h,al
in al,61h
mov ah,al
or al,3
out 61h,al
blip1:
mov cx,2801
spkr_on:
loop spkr_on
dec bx
jnz blip1
mov al,ah
out 61h,al
pop di
pop dx
pop cx
pop bx
pop ax
ret
hw_blip endp
endif
;
if debug
printregs proc ; Dump the registers to LPT1.
push_all
push ax
push si
push bp
mov si,offset axreg
call binasc
mov ax,bx
mov si,offset bxreg
call binasc
mov ax,cx
mov si,offset cxreg
call binasc
mov ax,dx
mov si,offset dxreg
call binasc
mov ax,ds
mov si,offset dsreg
call binasc
mov ax,es
mov si,offset esreg
call binasc
mov ax,bp
mov si,offset bpreg
call binasc
mov ax,di
mov si,offset direg
call binasc
pop bp
pop si
push si
push bp
mov ax,si
mov si,offset sireg
call binasc
mov si,offset prtstr ;String to output
pop bp
push dx ;Save DX
xor dx,dx ;Printer LPT1:
prloop:
mov ah,0 ;Print string
mov al,cs:[si]
cmp al,0
je prdone
int 17h
inc si
jmp prloop
prdone:
pop dx
pop si
pop ax
pop_all
ret
printregs endp
endif
;
if debug
binasc proc near ;Convert AX to ASCII and put at CS:SI
push ax
mov al,ah
call conval
pop ax
conval:
push ax
push cx
mov cl,4
ror al,cl
pop cx
and al,0Fh
add al,30h
cmp al,39h
jbe bin1
add al,7
bin1:
mov cs:[si],al
inc si
pop ax
and al,0Fh
add al,30h
cmp al,39h
jbe bin2
add al,7
bin2:
mov cs:[si],al
inc si
ret
binasc endp
endif
;
disk_error_msg proc ; display an error msg if I/O fails
push_all
mov si,offset cs:disk_msg ; display error message
mov bl,byte ptr cs:colour
call disp_str_colour
pop_all
ret
disk_error_msg endp
;
invalid_letter proc ; error message in reply to bad ALIAS cmd
push_all
mov si,offset cs:inv_letter
mov bl,byte ptr cs:colour
call disp_str_colour
pop_all
ret
invalid_letter endp
;
syntax_error proc
push_all
mov si,offset cs:syn_error
mov bl,byte ptr cs:colour
call disp_str_colour
pop_all
ret
syntax_error endp
;
ab_zap: ; de-install program
call are_you_sure ; do we really want to zap?
cmp byte ptr cs:confirm,1
je zap_sure ; carry on if user is sure
jmp bye ; else abandon
zap_sure:
push_m <ax,ds,dx>
mov ah,25h ; replace old int 21h vector that was
mov al,21h ; overwritten by Alias
mov dx,cs:old_vec_seg
mov ds,dx
mov dx,cs:old_vec_off
int 21h
pop_m <dx,ds,ax>
push bp
mov bp,dx
mov byte ptr ds:[bp+1],0 ; set length to 0 to stop ALIAS Z cmd
; being executed by DOS
mov byte ptr ds:[bp+2],CR ; put c/r terminator in buffer too
pop bp ; The ALIAS Z cmd can't be recalled
; with F3, as the routine that restores
; the char bufer doesn't get called now
; that alias is no longer resident.
;
push_m <es,ax,bx,cx,dx>
mov ah,35h ; int 2eh vector holds start of MCB's
mov al,2eh
int 21h ; int 2eh vector --> es:bx
mov bx,es
dec bx ; 1st MCB now at bx:0
mov es,bx
zap2:
mov es,bx
mov ax,word ptr es:3 ; size of block controlled by this MCB
mov cl,es:0 ; marker at start of MCB
mov dx,word ptr es:1 ; segment that controls this block
cmp dx,cs:new_vec_seg ; is block owned by alias.com?
jne zap1
mov word ptr es:1,0 ; free the block if owned by alias.com
zap1:
cmp cl,5ah ; if marker = 'Z' then no more MCB's
je zap3
add bx,ax ; else point to next MCB
inc bx
jmp short zap2 ; and do it all again
zap3:
pop_m <dx,cx,bx,ax,es>
push_all
mov bl,cs:colour ; display de-installation message
mov si,offset cs:zap_msg
call disp_str_colour
pop_all
call restore_flags
iret ; finish. Alias now de-installed.
;
; -----------------------------------------------------------------------
; D A T A A R E A
; -----------------------------------------------------------------------
;
exec: db 0eah ; far jmp instruction
old_vec_off dw 0 ; existing int 21h vector before installation
old_vec_seg dw 0
new_vec_off dw 0 ; new int 21h vector installed by this prog
new_vec_seg dw 0
command_cs dw 0 ; the address within command.com that ...
command_ip dw 0 ; ... called this program
prf_pos dw 0 ; record pos where command match starts
prf_cflag db 0 ; used by prf_compare proc
prf_multi db 0 ; detects multiple presses of prf_trigger key
it_multi db 0 ; detects multiple it_key presses
it_save dw 0 ; save cursorb for multiple F8 operations.
prf_bx dw 0 ; used by multi prf
csize db 1 ; 1 = small, 2 = big cursor size
def_fn_msg db 'Default data file is ',EOM
defdir_hdr db 'Z:\' ; Def_dir header.Drive letter to be filled in.
def_dir db 66 dup(0) ; Note the dir where ALIAS.DAT was loaded from.
default_fn db 'ALIAS.DAT',0 ; default filename
match db 'alias ' ; command looked for
match_u_case db 'ALIAS ' ; check upper case too
count_msg db CR,LF,'Aliases defined: ' ; used by ALIAS I.
count_msg1 db '00/' ; 00's filled by count_aliases
count_msg2 db '00',CR,LF,EOM
buffer db LHS_LEN dup(0) ; temporary store for user's string
buffer2 db LHS_LEN dup(0) ; used by D and L commands for searching
param_buff db 129 dup(0) ; save chars to be re-added after aliasing
nest_flag db 0 ; gets set if an expansion takes place
match_pos dw 0 ; offset into ab_table where match starts
match_len db 0 ; length of match string
arg_end db 0
str_end db 0
spare dw 0 ; position of spare entry in table
temp1 dw 0 ; temporary storage to avoid using stack
temp2 dw 0
temp3 dw 0
sort_counter db 0 ; used by sorting routine
sort_pointer dw 0 ; ditto
swap_flag db 0 ; ditto
sort_entries db 0 ; ditto
confirm db 0 ; set/cleared by are_you_sure proc
sure_msg db CR,LF,'Are you sure? (Y/N) ',EOM
press_msg db '>> Press any key to continue <<',EOM
kb_str_len db 0 ; save length of string got by func 0Ah
kb_str_ch1 db 0 ; save 1st char of str before setting to cr
do_kb_str db 0 ; do we want to put back str? 0 = no
echo_temp db 0 ; used by echo proc
echo_flag db 0 ; used by echo and disp_str_colour procs
list_temp db 0 ; used by list proc
list_temp2 dw 0 ; used by list proc
list_count db 0 ; counter so LIST can pause when screen full
page_len db 0 ; used in LIST proc
old_col db 0 ; save current colour during ALIAS C command
zap_msg db CR,LF,'ALIAS de-installed.',CR,LF,EOM
multi_line_outstanding db 0 ; is part of multi-line remaining? 0 = no
multi_start dw 0
multi_len db 0
save_flags dw 0 ; save the flags register here
error_msg db CR,LF,'Error - type ALIAS ? for help.',CR,LF,EOM
err_nfound db CR,LF,'No such alias.',EOM
exist_msg db CR,LF,'Specified alias already exists.',CR,LF,EOM
inv_letter db CR,LF,'Invalid command. Type ALIAS ? for help.',CR,LF,EOM
syn_error db CR,LF,'Syntax error. Type ALIAS ? for help.',EOM
disk_msg db CR,LF,'Disk error. Possibly File Not Found,'
db ' or Disk Full.',CR,LF,EOM
no_fit_msg db CR,LF,'Error - string too long.',CR,LF,EOM
star_flag db 0
table_full_msg db CR,LF,'No more space in Alias table.',CR,LF,EOM
left_sq_br db '[',0 ; for use if show mode is on
rght_sq_br db ']',0
command_letter db 0 ; single-char ALIAS command store
version db CR,LF
db 'ALIAS v',VERS,CR,LF
ife online_help
db '(Short version)',CR,LF
endif
db EOM
colour_msg db CR,'Press SPACE to see colours, RETURN to select'
db ' or ESC to quit.',EOM
msg_show db 'Expanded aliases will echo on screen.',CR,LF,EOM
msg_hide db 'Expanded aliases will not echo.',CR,LF,EOM
msg_off db 'Aliases are turned off.',CR,LF,EOM
msg_prompt db 'Aliases from DOS prompt only.',CR,LF,EOM
msg_global db 'Global expansion set.',CR,LF,EOM
if debug ; This data used by printregs proc
prtstr db 'AX-'
axreg db '----'
db ' BX-'
bxreg db '----'
db ' CX-'
cxreg db '----'
db ' DX-'
dxreg db '----'
db ' DS-'
dsreg db '----'
db ' ES-'
esreg db '----'
db ' BP-'
bpreg db '----'
db ' DI-'
direg db '----'
db ' SI-'
sireg db '----'
db CR,LF,0
endif
if online_help ; Only assemble online help if EQUate
; set. Omitting help saves memory.
help_text db LF,CR
db '╔═══════╤═════════════════════════════════════════════════════════╤════════════╗',CR,LF
db '║ v',VERS,' │ ALIAS Help Screen (Read ALIAS.HLP for more details) │ (c)RJS ''89║',CR,LF
db '╟───────┴─────────────────────────────────────────────────────────┴────────────╢',CR,LF
db '║ Make DA an alias for DIR A: ALIAS A DA DIR A: ║',CR,LF
db '║ Delete alias DA ALIAS D DA ║',CR,LF
db '║ List aliases ALIAS L aliasname ║',CR,LF
db '║ Read aliases from file (default ALIAS.DAT) ALIAS R filename ║',CR,LF
db '║ Write aliases to file (default ALIAS.DAT) ALIAS W filename ║',CR,LF
db '╟────────────────────────────────────────────────────┬─────────────────────────╢',CR,LF
db '║ Flush all aliases from memory ALIAS F │Recall commands ',24,' ║',CR,LF
db '║ Aliases valid from prompt only (default) ALIAS P │Separator & ║',CR,LF
db '║ Aliases valid globally ALIAS G │Override alias ~ ║',CR,LF
db '║ Aliases not valid (turn them off) ALIAS N │Beg/End of cmnds PgUp/Dn║',CR,LF
db '║ Show aliases on screen before expanding ALIAS S │Quit circular alias ESC║',CR,LF
db '║ Hide aliases (don''t show them) ALIAS H ├─────────────────────────╢',CR,LF
db '║ Display status and setup info ALIAS I │WordRt/Lt Ctrl ',26,'/Ctrl ',27,'║',CR,LF
db '║ Change colour used by ALIAS program ALIAS C │BegLn/EndLn Home/End║',CR,LF
db '║ De-install ALIAS ALIAS Z │DelWrdL/R Ctrl-W/Alt-W║',CR,LF
db '║ Display this help screen ALIAS ? │DBOL/DEOL Ctrl-L/Alt-L║',CR,LF
db '║ List contents of command recall buffer ALIAS B │Undelete Ctrl-U║',CR,LF
db '╟1─────┬2──────┬3───────┬4──────┬5──────┬6──────┬7───┴──┬8───────┬9─────┬10────╢',CR,LF
db '║ │ │ │ │ │ │ │Complete│ It │ Also ║',CR,LF
db '╚══════╧═══════╧════════╧═══════╧═══════╧═══════╧═══════╧════════╧══════╧══════╝',CR,LF
db EOM
else ; If no online help required, inform user.
help_text db LF,CR,' No online help available in short',CR,LF
db ' version. Read ALIAS.HLP file for help.',CR,LF,EOM
endif
; These 5 bytes get saved at the top of the
; data file.
table_top:
ins_mode db 0 ; 0 = overwrite mode, 1 = insert mode
ab_status db 1 ; alias status. 1 = on, 0 = off. This too
; is saved with table.
expand_from db 0 ; 0 = dos prompt (default), 1 = global. This
; gets saved with table-don't move this db.
colour db 7 ; default colour. changed with C command,
; and gets saved with table. 7 = white.
echo_status db 0 ; 0 = hide (default), 1 = show. also gets
; saved with table.
ab_table db ((RHS_LEN+LHS_LEN+1)*TBL_LEN) dup(0) ; the alias table
table_end db 0F0h ; used by count_aliases
;Data Area for Dos Editor
;Table of keys and their commands' address
cmndtbl:
dw ltarrw, curslf ;move cursor left one column
dw rtarrw, cursrt ;move cursor right one column
dw cntlf, wordl ;move cursor left word
dw cntrt, wordr ;move cursor right word
dw homekey, begline ;move cursor to beginning of line
dw endkey, endline ;move cursor to end of line
dw uparrw, cursup ;move cursor up one line
dw dnarrw, cursdn ;move cursor down one line
dw f3key, f3proc ;non-destructive f3
dw bs, delchrl ;delete char left of cursor
dw delkey, delchrr ;delete char right of cursor
dw 'W'-cntl, delwrdl ;delete word left of cursor
dw altw, delwrdr ;delete word right of cursor
dw 'L'-cntl, dellinl ;delete to beginning of line
dw altl, dellinr ;delete to end of line
dw altk, delline ;delete all characters on line
dw escape, escproc ;delete all characters on line
dw 'U'-cntl, undelet ;undelete text from buffer
dw altu, undelet ;undelete text from buffer
dw insert, inskey ;toggle insert/overwrite mode
dw prf_trigger,do_prf ;enter prf routine if trigger key pressed
dw it_key ,it_proc ;F8 key
dw also_key,also_proc ;F10 key
dw pgdnkey,pg_dn_proc ;PgDn key
dw pgupkey,pg_up_proc ;PgUp Key
dw f1key,f1proc ; F1 key does nothing
dw 0000h, nomatch ;no match, place the char in buffer
bublbeg db maxlin dup (?) ;beginning of bubble buffer
Bublend db ? ;end of bubble buffer
Cursorb dw ? ;pointer to beginning of cursor
Cursore dw ? ;pointer to end cursor in text buffer
Unleft dw ? ;undelete data counter on the left
Unright dw ? ;undelete data counter on the right
Scrnwdt dw ? ;screen width in columns
Disppag db ? ;display page
Maxchar dw ? ;max number of char in line
dcbuffer db maxlin+2 dup(?) ; Buffer for DOS compatibility
dcbufend db ? ; Mark end of dcbuffer
dcpointer dw ? ; pointer into dcbuffer
;Screen relative variables
Leftx dw ? ;X position of the left most character
edcursx dw ? ;X position of the editor cursor
cursorx dw ? ;X position of the cursor
cursory db ? ;Y position of the cursor
;Display line relative variables
linelen dw ? ;length of display line
Updatex dw ? ;X position for character update
;Text line relative variables
startx dw ? ;column # of start of the display line
scrnimg db maxswdt dup (?) ;image of screen display line
dosvect dd ? ;contains pointer to Dos vector
oldsp dd ? ;contains old stack pointer
codeseg dw ? ;code segment for this program
;Storage for the command recording functions
cmdtop db cmdlen-1 dup (?);ring buffer for line entries
cmdbot db ? ;end of ring buffer
cmdold dw ? ;pointer to oldest command
cmdnew dw ? ;pointer to newest command
cmdpnt dw ? ;pointer to current command
stckbot db 200 dup (?) ;storage for the stack
stcktop db ? ;top of the stack
;End of editor data
; -----------------------------------------------------------------------
; NOTHING BELOW HERE GETS MADE RESIDENT
; -----------------------------------------------------------------------
init: push cs ; set ds = cs
pop ds
jmp install
greet db 'ALIAS v',VERS,' now installed.'
ife online_help
db CR,LF,'(Short version. No online help).'
endif
db CR,LF,'(c)Robert Schifreen 1989.'
db CR,LF
db CR,LF,'ALIAS gives you:'
db CR,LF,' - Aliasing for MS-DOS commands'
db CR,LF,' - Recall of previous commands'
db CR,LF,' - Full editing of recalled commands'
db CR,LF,' - Automatic command completion.'
db CR,LF,'For help, use the ALIAS ? command.',CR,LF
db CR,LF,'IMPORTANT: ALIAS is not "free software" and it is not "public domain".'
db CR,LF,'You may use the software for one month, and you are welcome to give'
db CR,LF,'copies to anyone you wish. If, after the one month trial period, you'
db CR,LF,'intend to continue using the program, you or your company must register it'
db CR,LF,'by sending a contribution of up to £25 or 30 US dollars to the author at'
db CR,LF,'65 Latchingdon Court, 26 Forest Road, London, E17 6JT, England.',CR,LF
db CR,LF,'Registered users receive: extra documentation; news of major upgrades;'
db CR,LF,'a special memory-saving version; dial-up technical support in the UK'
db CR,LF,'and the US on the Cix and Bix networks; full MASM source code (¼MB) for'
db CR,LF,'the latest version of ALIAS (please state disk size when registering).'
db CR,LF,'$'
wrong_dos db 'ALIAS runs only under DOS version 2, 3 or 4.',CR,LF,DOS_EOM
alrdy_in db 'There seems to be a copy of ALIAS already in memory.',CR,LF
db 'Type ALIAS ? for help.',CR,LF,EOM
default db 'Loading ALIAS.DAT...',CR,LF,DOS_EOM
install:
; With ALIAS installed, calling DOS
; function 35h increments 0040:00F4h
; to show that ALIAS is resident. Use
; this check to see if prog is
; already installed.
push_m <ax,bx,cx,ds,dx,es>
mov ax,40h
mov ds,ax ; segment for ICA
mov ch,byte ptr ds:0f4h ; get current value of ICA byte
mov ah,35h ; now call function 35h
mov al,5 ; get value of int 5, though exact value
; doesn't really matter.
int 21h ; gets int 5 vector into es:bx
mov ax,40h ; point to ica again
mov ds,ax
mov cl,byte ptr ds:0f4h ; get ICA byte again.
inc ch
cmp ch,cl ; Is cl = ch + 1?
pop_m <es,dx,ds,cx,bx,ax>
jne carry_on_installing ; If cl becomes ch+1, then increment
; took place so ALIAS is resident.
; ALIAS is already loaded so don't
; load it again.
push_all
mov si,offset cs:alrdy_in
mov bl,cs:colour
call disp_str_colour ; display message
pop_all
int 20h ; terminate execution of ALIAS.COM
carry_on_installing:
push_m <ax,dx,ds>
mov ah,30h ; get DOS version number
int 21h
cmp al,2
pop_m <ds,dx,ax>
je dos_ok ; continue if 2
push_m <ax,dx,ds>
mov ah,30h ; get it again
int 21h
cmp al,3
pop_m <ds,dx,ax>
je dos_ok ; continue if it's a 3
push_m <ax,dx,ds>
mov ah,30h ; get it again
int 21h
cmp al,4
pop_m <ds,dx,ax>
je dos_ok ; continue if it's a 4
push_m <ax,dx,ds>
mov ah,30h ; get it again
int 21h
cmp al,0Ah
pop_m <ds,dx,ax>
je dos_ok ; continue if 10, ie DOS box of OS/2
mov ah,9 ; display error msg if DOS is not 2 or 3
mov dx,offset wrong_dos
push ds
push cs
pop ds
int 21h
pop ds
ret ; and terminate
dos_ok:
mov ah,35h ; get interrupt vector
mov al,21h ; number 21h - dos function call
int 021h
mov ax,es
mov cs:old_vec_seg,ax
mov cs:old_vec_off,bx
;
mov ah,25h ; set interrupt vector
mov al,21h ; specify vector to be set
mov dx,offset intent
int 21h
;
mov ah,35h ; find out new interrupt vector
mov al,21h ; for int 21h
int 21h
mov ax,es
mov cs:new_vec_seg,ax
mov cs:new_vec_off,bx
;
; If alias.dat exists, load it
push_m <ax,bx,cx,dx,ds>
push cs ; point to filename
pop ds
mov dx,offset cs:default_fn
mov ah,3dh ; open file
mov al,0 ; for reading
int 21h
jc no_default_file ; quit if file not found
;
; print msg to say we're loading file
push_all
mov ah,9
mov dx,offset cs:default
push cs
pop ds
int 21h
pop_all
;
mov bx,ax ; put handle in correct place
mov cx,((RHS_LEN + LHS_LEN + 1) * TBL_LEN) + 5 ; table plus signat
push cs
pop ds
mov dx,offset cs:table_top ; start of data area
mov ah,3fh
int 21h
;
mov ah,3eh ; close file
int 21h
;
; Get the name of the current directory,
; ie the one that ALIAS.DAT is in.
; Use this directory for future writes
; if an ALIAS W command is used without
; a specified filename.
push_m <ax,ds,dx,si>
mov ah,47h
mov dl,0 ; default drive
push cs
pop ds
mov si,offset cs:def_dir ; buffer for the directory
int 21h
pop_m <si,dx,ds,ax>
;
; Func 47h doesn't return the drive
; letter, so get it and plug it in.
push ax
mov ah,19h
int 21h ; get zero-based drive code into al.
add al,'A' ; convert to a letter
mov byte ptr cs:defdir_hdr,al ; and put it at front of string
pop ax
;
; Now find the end of the path string,
; and put a backslash and filename on,
; to create a full path and file name.
push_all
push cs
pop es ; scasb needs string at es:di
cld ; clear direction flag
mov al,0 ; char to search for
mov cx,66 ; length of string to search
mov di,offset cs:def_dir ; addr of string to search
repne scasb ; search till we find a 0. We will
; definitely find one eventually!
dec di ; di now has adr of the zero byte
cmp byte ptr cs:[di-1],'\' ; Are we in root?
je in_root ; Yes, then backslash is already there
mov byte ptr cs:[di],'\' ; else put backslash on end of string
; Now copy the default filename from
; default_fn to the end of the path.
inc di ; point to char after trailing backslash
in_root:
mov si,offset cs:default_fn ; point to start of default filename
copy1:
lodsb ; get a byte from the filename into al
cmp al,0 ; done?
je copy_done
mov byte ptr cs:[di],al ; put the byte into place
inc di ; SI got incremented by the lodsb.
jmp short copy1 ; and go get the next byte
copy_done:
pop_all
no_default_file: ; default file was not in current dir
; so don't load it.
pop_m <ds,dx,cx,bx,ax>
show greet ; Display welcome message. Note that
; we use the standard DOS call to display
; this message, rather than the fancy
; colour string printer that is used
; everywhere else in ALIAS. This is so
; that the user can redirect the greet
; message to NUL if he wishes.
; Set up the command line editor
mov sp,offset stcktop ;set stack pointer to top of stack
mov cs:codeseg,cs ;save this code segment
mov ds,cs:codeseg ;DS is same as code segment
call inittny ;initialize the editor
; Free the environment block allocated
; to us, as we don't need it. The adr
; of the block is in PSP:2ch.
; If the debug flag is set, do not
; assemble this routine. With the
; environment intact, one can use SMAP
; to find the name of the loaded version
; of the program, which helps me to
; remember whether ALIAS.COM is loaded,
; or whether it's a temporary version of
; the file, used for test purposes.
ife debug
push_m <ax,es>
mov es,cs:[2ch] ; get seg adr of our environment block
mov ah,49h ; free a block
int 21h ; free the block
pop_m <es,ax> ; all done
endif
mov ax,3100h ; terminate and remain resident
mov dx,rsize ; size of residency in paragraphs
int 21h ; done
code ends
end start ; start execution at routine 'start'
; -----------------------------------------------------------------------
; (c) Robert Schifreen 1985,1989
; -----------------------------------------------------------------------